blob: 3629cacd7c45ed5ac70a2df244cd1f3823e2e1e4 [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"
bellard93ac68b2003-09-30 20:57:29 +000021#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000022#include "disas.h"
bellard7d132992003-03-06 23:23:54 +000023
bellardfbf9eeb2004-04-25 21:21:33 +000024#if !defined(CONFIG_SOFTMMU)
25#undef EAX
26#undef ECX
27#undef EDX
28#undef EBX
29#undef ESP
30#undef EBP
31#undef ESI
32#undef EDI
33#undef EIP
34#include <signal.h>
35#include <sys/ucontext.h>
36#endif
37
bellard36bdbe52003-11-19 22:12:02 +000038int tb_invalidated_flag;
39
bellarddc990652003-03-19 00:00:28 +000040//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000041//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000042
bellarde4533c72003-06-15 19:51:39 +000043void cpu_loop_exit(void)
44{
thsbfed01f2007-06-03 17:44:37 +000045 /* NOTE: the register at this point must be saved by hand because
46 longjmp restore them */
47 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000048 longjmp(env->jmp_env, 1);
49}
thsbfed01f2007-06-03 17:44:37 +000050
pbrooke6e59062006-10-22 00:18:54 +000051#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +000052#define reg_T2
53#endif
bellarde4533c72003-06-15 19:51:39 +000054
bellardfbf9eeb2004-04-25 21:21:33 +000055/* exit the current TB from a signal handler. The host registers are
56 restored in a state compatible with the CPU emulator
57 */
ths5fafdf22007-09-16 21:08:06 +000058void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000059{
60#if !defined(CONFIG_SOFTMMU)
61 struct ucontext *uc = puc;
62#endif
63
64 env = env1;
65
66 /* XXX: restore cpu registers saved in host registers */
67
68#if !defined(CONFIG_SOFTMMU)
69 if (puc) {
70 /* XXX: use siglongjmp ? */
71 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
72 }
73#endif
74 longjmp(env->jmp_env, 1);
75}
76
bellard8a40a182005-11-20 10:35:40 +000077
78static TranslationBlock *tb_find_slow(target_ulong pc,
79 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +000080 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +000081{
82 TranslationBlock *tb, **ptb1;
83 int code_gen_size;
84 unsigned int h;
85 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
86 uint8_t *tc_ptr;
ths3b46e622007-09-17 08:09:54 +000087
bellard8a40a182005-11-20 10:35:40 +000088 spin_lock(&tb_lock);
89
90 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +000091
bellard8a40a182005-11-20 10:35:40 +000092 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +000093
bellard8a40a182005-11-20 10:35:40 +000094 /* find translated block using physical mappings */
95 phys_pc = get_phys_addr_code(env, pc);
96 phys_page1 = phys_pc & TARGET_PAGE_MASK;
97 phys_page2 = -1;
98 h = tb_phys_hash_func(phys_pc);
99 ptb1 = &tb_phys_hash[h];
100 for(;;) {
101 tb = *ptb1;
102 if (!tb)
103 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000104 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000105 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000106 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000107 tb->flags == flags) {
108 /* check next page if needed */
109 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000110 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000111 TARGET_PAGE_SIZE;
112 phys_page2 = get_phys_addr_code(env, virt_page2);
113 if (tb->page_addr[1] == phys_page2)
114 goto found;
115 } else {
116 goto found;
117 }
118 }
119 ptb1 = &tb->phys_hash_next;
120 }
121 not_found:
122 /* if no translated code available, then translate it now */
123 tb = tb_alloc(pc);
124 if (!tb) {
125 /* flush must be done */
126 tb_flush(env);
127 /* cannot fail at this point */
128 tb = tb_alloc(pc);
129 /* don't forget to invalidate previous TB info */
bellard15388002005-12-19 01:42:32 +0000130 tb_invalidated_flag = 1;
bellard8a40a182005-11-20 10:35:40 +0000131 }
132 tc_ptr = code_gen_ptr;
133 tb->tc_ptr = tc_ptr;
134 tb->cs_base = cs_base;
135 tb->flags = flags;
136 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
137 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
ths3b46e622007-09-17 08:09:54 +0000138
bellard8a40a182005-11-20 10:35:40 +0000139 /* check next page if needed */
140 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
141 phys_page2 = -1;
142 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
143 phys_page2 = get_phys_addr_code(env, virt_page2);
144 }
145 tb_link_phys(tb, phys_pc, phys_page2);
ths3b46e622007-09-17 08:09:54 +0000146
bellard8a40a182005-11-20 10:35:40 +0000147 found:
bellard8a40a182005-11-20 10:35:40 +0000148 /* we add the TB in the virtual pc hash table */
149 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
150 spin_unlock(&tb_lock);
151 return tb;
152}
153
154static inline TranslationBlock *tb_find_fast(void)
155{
156 TranslationBlock *tb;
157 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000158 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000159
160 /* we record a subset of the CPU state. It will
161 always be the same before a given translated block
162 is executed. */
163#if defined(TARGET_I386)
164 flags = env->hflags;
165 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
ths0573fbf2007-09-23 15:28:04 +0000166 flags |= env->intercept;
bellard8a40a182005-11-20 10:35:40 +0000167 cs_base = env->segs[R_CS].base;
168 pc = cs_base + env->eip;
169#elif defined(TARGET_ARM)
170 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000171 | (env->vfp.vec_stride << 4);
172 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
173 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000174 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
175 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000176 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000177 cs_base = 0;
178 pc = env->regs[15];
179#elif defined(TARGET_SPARC)
180#ifdef TARGET_SPARC64
bellarda80dde02006-06-26 19:53:29 +0000181 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
182 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
183 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000184#else
blueswir16d5f2372007-11-07 17:03:37 +0000185 // FPU enable . Supervisor
186 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000187#endif
188 cs_base = env->npc;
189 pc = env->pc;
190#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000191 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000192 cs_base = 0;
193 pc = env->nip;
194#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000195 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000196 cs_base = 0;
thsead93602007-09-06 00:18:15 +0000197 pc = env->PC[env->current_tc];
pbrooke6e59062006-10-22 00:18:54 +0000198#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000199 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
200 | (env->sr & SR_S) /* Bit 13 */
201 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000202 cs_base = 0;
203 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000204#elif defined(TARGET_SH4)
ths823029f2007-12-02 06:10:04 +0000205 flags = env->flags;
206 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000207 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000208#elif defined(TARGET_ALPHA)
209 flags = env->ps;
210 cs_base = 0;
211 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000212#elif defined(TARGET_CRIS)
213 flags = 0;
214 cs_base = 0;
215 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000216#else
217#error unsupported CPU
218#endif
219 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
220 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
221 tb->flags != flags, 0)) {
222 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000223 /* Note: we do it here to avoid a gcc bug on Mac OS X when
224 doing it in tb_find_slow */
225 if (tb_invalidated_flag) {
226 /* as some TB could have been invalidated because
227 of memory exceptions while generating the code, we
228 must recompute the hash index here */
229 T0 = 0;
230 }
bellard8a40a182005-11-20 10:35:40 +0000231 }
232 return tb;
233}
234
pbrook497ad682007-11-23 02:11:10 +0000235#if defined(__sparc__) && !defined(HOST_SOLARIS)
236#define BREAK_CHAIN tmp_T0 = 0
237#else
238#define BREAK_CHAIN T0 = 0
239#endif
bellard8a40a182005-11-20 10:35:40 +0000240
bellard7d132992003-03-06 23:23:54 +0000241/* main execution loop */
242
bellarde4533c72003-06-15 19:51:39 +0000243int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000244{
pbrook1057eaa2007-02-04 13:37:44 +0000245#define DECLARE_HOST_REGS 1
246#include "hostregs_helper.h"
247#if defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000248#if defined(reg_REGWPTR)
249 uint32_t *saved_regwptr;
250#endif
251#endif
bellardfdbb4692006-06-14 17:32:25 +0000252#if defined(__sparc__) && !defined(HOST_SOLARIS)
thsb49d07b2007-02-02 03:57:09 +0000253 int saved_i7;
254 target_ulong tmp_T0;
bellard8c6939c2003-06-09 15:28:00 +0000255#endif
bellard8a40a182005-11-20 10:35:40 +0000256 int ret, interrupt_request;
bellard7d132992003-03-06 23:23:54 +0000257 void (*gen_func)(void);
bellard8a40a182005-11-20 10:35:40 +0000258 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000259 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000260
thsbfed01f2007-06-03 17:44:37 +0000261 if (cpu_halted(env1) == EXCP_HALTED)
262 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000263
ths5fafdf22007-09-16 21:08:06 +0000264 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000265
bellard7d132992003-03-06 23:23:54 +0000266 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000267#define SAVE_HOST_REGS 1
268#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000269 env = env1;
bellardfdbb4692006-06-14 17:32:25 +0000270#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellarde4533c72003-06-15 19:51:39 +0000271 /* we also save i7 because longjmp may not restore it */
272 asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
273#endif
274
bellard0d1a29f2004-10-12 22:01:28 +0000275 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000276#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000277 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000278 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
279 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000280 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000281 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000282#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000283#if defined(reg_REGWPTR)
284 saved_regwptr = REGWPTR;
285#endif
pbrooke6e59062006-10-22 00:18:54 +0000286#elif defined(TARGET_M68K)
287 env->cc_op = CC_OP_FLAGS;
288 env->cc_dest = env->sr & 0xf;
289 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000290#elif defined(TARGET_ALPHA)
291#elif defined(TARGET_ARM)
292#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000293#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000294#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000295#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000296 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000297#else
298#error unsupported target CPU
299#endif
bellard3fb2ded2003-06-24 13:22:59 +0000300 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000301
bellard7d132992003-03-06 23:23:54 +0000302 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000303 for(;;) {
304 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000305 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000306 /* if an exception is pending, we execute it here */
307 if (env->exception_index >= 0) {
308 if (env->exception_index >= EXCP_INTERRUPT) {
309 /* exit request from the cpu execution loop */
310 ret = env->exception_index;
311 break;
312 } else if (env->user_mode_only) {
313 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000314 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000315 loop */
bellard83479e72003-06-25 16:12:37 +0000316#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000317 do_interrupt_user(env->exception_index,
318 env->exception_is_int,
319 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000320 env->exception_next_eip);
bellard83479e72003-06-25 16:12:37 +0000321#endif
bellard3fb2ded2003-06-24 13:22:59 +0000322 ret = env->exception_index;
323 break;
324 } else {
bellard83479e72003-06-25 16:12:37 +0000325#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000326 /* simulate a real cpu exception. On i386, it can
327 trigger new exceptions, but we do not handle
328 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000329 do_interrupt(env->exception_index,
330 env->exception_is_int,
331 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000332 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000333 /* successfully delivered */
334 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000335#elif defined(TARGET_PPC)
336 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000337#elif defined(TARGET_MIPS)
338 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000339#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000340 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000341#elif defined(TARGET_ARM)
342 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000343#elif defined(TARGET_SH4)
344 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000345#elif defined(TARGET_ALPHA)
346 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000347#elif defined(TARGET_CRIS)
348 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000349#elif defined(TARGET_M68K)
350 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000351#endif
bellard3fb2ded2003-06-24 13:22:59 +0000352 }
353 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000354 }
bellard9df217a2005-02-10 22:05:51 +0000355#ifdef USE_KQEMU
356 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
357 int ret;
358 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
359 ret = kqemu_cpu_exec(env);
360 /* put eflags in CPU temporary format */
361 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
362 DF = 1 - (2 * ((env->eflags >> 10) & 1));
363 CC_OP = CC_OP_EFLAGS;
364 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
365 if (ret == 1) {
366 /* exception */
367 longjmp(env->jmp_env, 1);
368 } else if (ret == 2) {
369 /* softmmu execution needed */
370 } else {
371 if (env->interrupt_request != 0) {
372 /* hardware interrupt will be executed just after */
373 } else {
374 /* otherwise, we restart */
375 longjmp(env->jmp_env, 1);
376 }
377 }
bellard9de5e442003-03-23 16:49:39 +0000378 }
bellard9df217a2005-02-10 22:05:51 +0000379#endif
380
bellard3fb2ded2003-06-24 13:22:59 +0000381 T0 = 0; /* force lookup of first TB */
382 for(;;) {
bellardfdbb4692006-06-14 17:32:25 +0000383#if defined(__sparc__) && !defined(HOST_SOLARIS)
ths5fafdf22007-09-16 21:08:06 +0000384 /* g1 can be modified by some libc? functions */
bellard3fb2ded2003-06-24 13:22:59 +0000385 tmp_T0 = T0;
ths3b46e622007-09-17 08:09:54 +0000386#endif
bellard68a79312003-06-30 13:12:32 +0000387 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000388 if (__builtin_expect(interrupt_request, 0)
389#if defined(TARGET_I386)
390 && env->hflags & HF_GIF_MASK
391#endif
392 ) {
pbrook6658ffb2007-03-16 23:58:11 +0000393 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
394 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
395 env->exception_index = EXCP_DEBUG;
396 cpu_loop_exit();
397 }
balroga90b7312007-05-01 01:28:01 +0000398#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000399 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000400 if (interrupt_request & CPU_INTERRUPT_HALT) {
401 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
402 env->halted = 1;
403 env->exception_index = EXCP_HLT;
404 cpu_loop_exit();
405 }
406#endif
bellard68a79312003-06-30 13:12:32 +0000407#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000408 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
409 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000410 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000411 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
412 do_smm_enter();
pbrook497ad682007-11-23 02:11:10 +0000413 BREAK_CHAIN;
bellard3b21e032006-09-24 18:41:56 +0000414 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000415 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000416 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000417 int intno;
ths0573fbf2007-09-23 15:28:04 +0000418 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000419 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000420 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000421 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000422 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
423 }
bellardd05e66d2003-08-20 21:34:35 +0000424 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000425 /* ensure that no TB jump will be modified as
426 the program flow was changed */
pbrook497ad682007-11-23 02:11:10 +0000427 BREAK_CHAIN;
ths0573fbf2007-09-23 15:28:04 +0000428#if !defined(CONFIG_USER_ONLY)
429 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
430 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
431 int intno;
432 /* FIXME: this should respect TPR */
433 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000434 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000435 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
436 if (loglevel & CPU_LOG_TB_IN_ASM)
437 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
438 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000439 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
440 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
pbrook497ad682007-11-23 02:11:10 +0000441 BREAK_CHAIN;
ths0573fbf2007-09-23 15:28:04 +0000442#endif
bellard68a79312003-06-30 13:12:32 +0000443 }
bellardce097762004-01-04 23:53:18 +0000444#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000445#if 0
446 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
447 cpu_ppc_reset(env);
448 }
449#endif
j_mayer47103572007-03-30 09:38:04 +0000450 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000451 ppc_hw_interrupt(env);
452 if (env->pending_interrupts == 0)
453 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
pbrook497ad682007-11-23 02:11:10 +0000454 BREAK_CHAIN;
bellardce097762004-01-04 23:53:18 +0000455 }
bellard6af0bf92005-07-02 14:58:51 +0000456#elif defined(TARGET_MIPS)
457 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000458 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000459 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000460 !(env->CP0_Status & (1 << CP0St_EXL)) &&
461 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000462 !(env->hflags & MIPS_HFLAG_DM)) {
463 /* Raise it */
464 env->exception_index = EXCP_EXT_INTERRUPT;
465 env->error_code = 0;
466 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000467 BREAK_CHAIN;
bellard6af0bf92005-07-02 14:58:51 +0000468 }
bellarde95c8d52004-09-30 22:22:08 +0000469#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000470 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
471 (env->psret != 0)) {
472 int pil = env->interrupt_index & 15;
473 int type = env->interrupt_index & 0xf0;
474
475 if (((type == TT_EXTINT) &&
476 (pil == 15 || pil > env->psrpil)) ||
477 type != TT_EXTINT) {
478 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
479 do_interrupt(env->interrupt_index);
480 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000481#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
482 cpu_check_irqs(env);
483#endif
pbrook497ad682007-11-23 02:11:10 +0000484 BREAK_CHAIN;
bellard66321a12005-04-06 20:47:48 +0000485 }
bellarde95c8d52004-09-30 22:22:08 +0000486 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
487 //do_interrupt(0, 0, 0, 0, 0);
488 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000489 }
bellardb5ff1b32005-11-26 10:38:39 +0000490#elif defined(TARGET_ARM)
491 if (interrupt_request & CPU_INTERRUPT_FIQ
492 && !(env->uncached_cpsr & CPSR_F)) {
493 env->exception_index = EXCP_FIQ;
494 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000495 BREAK_CHAIN;
bellardb5ff1b32005-11-26 10:38:39 +0000496 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000497 /* ARMv7-M interrupt return works by loading a magic value
498 into the PC. On real hardware the load causes the
499 return to occur. The qemu implementation performs the
500 jump normally, then does the exception return when the
501 CPU tries to execute code at the magic address.
502 This will cause the magic PC value to be pushed to
503 the stack if an interrupt occured at the wrong time.
504 We avoid this by disabling interrupts when
505 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000506 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000507 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
508 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000509 env->exception_index = EXCP_IRQ;
510 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000511 BREAK_CHAIN;
bellardb5ff1b32005-11-26 10:38:39 +0000512 }
bellardfdf9b3e2006-04-27 21:07:38 +0000513#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000514 if (interrupt_request & CPU_INTERRUPT_HARD) {
515 do_interrupt(env);
516 BREAK_CHAIN;
517 }
j_mayereddf68a2007-04-05 07:22:49 +0000518#elif defined(TARGET_ALPHA)
519 if (interrupt_request & CPU_INTERRUPT_HARD) {
520 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000521 BREAK_CHAIN;
j_mayereddf68a2007-04-05 07:22:49 +0000522 }
thsf1ccf902007-10-08 13:16:14 +0000523#elif defined(TARGET_CRIS)
524 if (interrupt_request & CPU_INTERRUPT_HARD) {
525 do_interrupt(env);
526 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
pbrook497ad682007-11-23 02:11:10 +0000527 BREAK_CHAIN;
thsf1ccf902007-10-08 13:16:14 +0000528 }
pbrook06338792007-05-23 19:58:11 +0000529#elif defined(TARGET_M68K)
530 if (interrupt_request & CPU_INTERRUPT_HARD
531 && ((env->sr & SR_I) >> SR_I_SHIFT)
532 < env->pending_level) {
533 /* Real hardware gets the interrupt vector via an
534 IACK cycle at this point. Current emulated
535 hardware doesn't rely on this, so we
536 provide/save the vector when the interrupt is
537 first signalled. */
538 env->exception_index = env->pending_vector;
539 do_interrupt(1);
pbrook497ad682007-11-23 02:11:10 +0000540 BREAK_CHAIN;
pbrook06338792007-05-23 19:58:11 +0000541 }
bellard68a79312003-06-30 13:12:32 +0000542#endif
bellard9d050952006-05-22 22:03:52 +0000543 /* Don't use the cached interupt_request value,
544 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000545 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000546 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
547 /* ensure that no TB jump will be modified as
548 the program flow was changed */
pbrook497ad682007-11-23 02:11:10 +0000549 BREAK_CHAIN;
bellardbf3e8bf2004-02-16 21:58:54 +0000550 }
bellard68a79312003-06-30 13:12:32 +0000551 if (interrupt_request & CPU_INTERRUPT_EXIT) {
552 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
553 env->exception_index = EXCP_INTERRUPT;
554 cpu_loop_exit();
555 }
bellard3fb2ded2003-06-24 13:22:59 +0000556 }
557#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000558 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000559 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000560 regs_to_env();
561#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000562 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000563 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000564 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000565#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000566 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000567#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000568 REGWPTR = env->regbase + (env->cwp * 16);
569 env->regwptr = REGWPTR;
570 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000571#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000572 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000573#elif defined(TARGET_M68K)
574 cpu_m68k_flush_flags(env, env->cc_op);
575 env->cc_op = CC_OP_FLAGS;
576 env->sr = (env->sr & 0xffe0)
577 | env->cc_dest | (env->cc_x << 4);
578 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000579#elif defined(TARGET_MIPS)
580 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000581#elif defined(TARGET_SH4)
582 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000583#elif defined(TARGET_ALPHA)
584 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000585#elif defined(TARGET_CRIS)
586 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000587#else
ths5fafdf22007-09-16 21:08:06 +0000588#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000589#endif
bellard3fb2ded2003-06-24 13:22:59 +0000590 }
bellard7d132992003-03-06 23:23:54 +0000591#endif
bellard8a40a182005-11-20 10:35:40 +0000592 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000593#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000594 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000595 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
596 (long)tb->tc_ptr, tb->pc,
597 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000598 }
bellard9d27abd2003-05-10 13:13:54 +0000599#endif
bellardfdbb4692006-06-14 17:32:25 +0000600#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard3fb2ded2003-06-24 13:22:59 +0000601 T0 = tmp_T0;
ths3b46e622007-09-17 08:09:54 +0000602#endif
bellard8a40a182005-11-20 10:35:40 +0000603 /* see if we can patch the calling TB. When the TB
604 spans two pages, we cannot safely do a direct
605 jump. */
bellardc27004e2005-01-03 23:35:10 +0000606 {
bellard8a40a182005-11-20 10:35:40 +0000607 if (T0 != 0 &&
bellardf32fc642006-02-08 22:43:39 +0000608#if USE_KQEMU
609 (env->kqemu_enabled != 2) &&
610#endif
bellardec6338b2007-11-08 14:25:03 +0000611 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000612 spin_lock(&tb_lock);
bellardc27004e2005-01-03 23:35:10 +0000613 tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000614 spin_unlock(&tb_lock);
615 }
bellardc27004e2005-01-03 23:35:10 +0000616 }
bellard3fb2ded2003-06-24 13:22:59 +0000617 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000618 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000619 /* execute the generated code */
620 gen_func = (void *)tc_ptr;
621#if defined(__sparc__)
622 __asm__ __volatile__("call %0\n\t"
623 "mov %%o7,%%i0"
624 : /* no outputs */
ths5fafdf22007-09-16 21:08:06 +0000625 : "r" (gen_func)
bellardfdbb4692006-06-14 17:32:25 +0000626 : "i0", "i1", "i2", "i3", "i4", "i5",
thsfaab7592007-03-19 20:39:49 +0000627 "o0", "o1", "o2", "o3", "o4", "o5",
bellardfdbb4692006-06-14 17:32:25 +0000628 "l0", "l1", "l2", "l3", "l4", "l5",
629 "l6", "l7");
bellard3fb2ded2003-06-24 13:22:59 +0000630#elif defined(__arm__)
631 asm volatile ("mov pc, %0\n\t"
632 ".global exec_loop\n\t"
633 "exec_loop:\n\t"
634 : /* no outputs */
635 : "r" (gen_func)
636 : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
bellardb8076a72005-04-07 22:20:31 +0000637#elif defined(__ia64)
638 struct fptr {
639 void *ip;
640 void *gp;
641 } fp;
642
643 fp.ip = tc_ptr;
644 fp.gp = code_gen_buffer + 2 * (1 << 20);
645 (*(void (*)(void)) &fp)();
bellard3fb2ded2003-06-24 13:22:59 +0000646#else
647 gen_func();
648#endif
bellard83479e72003-06-25 16:12:37 +0000649 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000650 /* reset soft MMU for next block (it can currently
651 only be set by a memory fault) */
652#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000653 if (env->hflags & HF_SOFTMMU_MASK) {
654 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000655 /* do not allow linking to another block */
656 T0 = 0;
657 }
658#endif
bellardf32fc642006-02-08 22:43:39 +0000659#if defined(USE_KQEMU)
660#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
661 if (kqemu_is_ok(env) &&
662 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
663 cpu_loop_exit();
664 }
665#endif
ths50a518e2007-06-03 18:52:15 +0000666 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000667 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000668 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000669 }
bellard3fb2ded2003-06-24 13:22:59 +0000670 } /* for(;;) */
671
bellard7d132992003-03-06 23:23:54 +0000672
bellarde4533c72003-06-15 19:51:39 +0000673#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000674 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000675 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000676#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000677 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000678#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000679#if defined(reg_REGWPTR)
680 REGWPTR = saved_regwptr;
681#endif
bellard67867302003-11-23 17:05:30 +0000682#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000683#elif defined(TARGET_M68K)
684 cpu_m68k_flush_flags(env, env->cc_op);
685 env->cc_op = CC_OP_FLAGS;
686 env->sr = (env->sr & 0xffe0)
687 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000688#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000689#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000690#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000691#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000692 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000693#else
694#error unsupported target CPU
695#endif
pbrook1057eaa2007-02-04 13:37:44 +0000696
697 /* restore global registers */
bellardfdbb4692006-06-14 17:32:25 +0000698#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard8c6939c2003-06-09 15:28:00 +0000699 asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
700#endif
pbrook1057eaa2007-02-04 13:37:44 +0000701#include "hostregs_helper.h"
702
bellard6a00d602005-11-21 23:25:50 +0000703 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000704 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000705 return ret;
706}
bellard6dbad632003-03-16 18:05:05 +0000707
bellardfbf9eeb2004-04-25 21:21:33 +0000708/* must only be called from the generated code as an exception can be
709 generated */
710void tb_invalidate_page_range(target_ulong start, target_ulong end)
711{
bellarddc5d0b32004-06-22 18:43:30 +0000712 /* XXX: cannot enable it yet because it yields to MMU exception
713 where NIP != read address on PowerPC */
714#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000715 target_ulong phys_addr;
716 phys_addr = get_phys_addr_code(env, start);
717 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000718#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000719}
720
bellard1a18c712003-10-30 01:07:51 +0000721#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000722
bellard6dbad632003-03-16 18:05:05 +0000723void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
724{
725 CPUX86State *saved_env;
726
727 saved_env = env;
728 env = s;
bellarda412ac52003-07-26 18:01:40 +0000729 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000730 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000731 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000732 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000733 } else {
bellardb453b702004-01-04 15:45:21 +0000734 load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000735 }
bellard6dbad632003-03-16 18:05:05 +0000736 env = saved_env;
737}
bellard9de5e442003-03-23 16:49:39 +0000738
bellard6f12a2a2007-11-11 22:16:56 +0000739void cpu_x86_fsave(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_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000747
748 env = saved_env;
749}
750
bellard6f12a2a2007-11-11 22:16:56 +0000751void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000752{
753 CPUX86State *saved_env;
754
755 saved_env = env;
756 env = s;
ths3b46e622007-09-17 08:09:54 +0000757
bellard6f12a2a2007-11-11 22:16:56 +0000758 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000759
760 env = saved_env;
761}
762
bellarde4533c72003-06-15 19:51:39 +0000763#endif /* TARGET_I386 */
764
bellard67b915a2004-03-31 23:37:16 +0000765#if !defined(CONFIG_SOFTMMU)
766
bellard3fb2ded2003-06-24 13:22:59 +0000767#if defined(TARGET_I386)
768
bellardb56dad12003-05-08 15:38:04 +0000769/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000770 the effective address of the memory exception. 'is_write' is 1 if a
771 write caused the exception and otherwise 0'. 'old_set' is the
772 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000773static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000774 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000775 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000776{
bellarda513fe12003-05-27 23:29:48 +0000777 TranslationBlock *tb;
778 int ret;
bellard68a79312003-06-30 13:12:32 +0000779
bellard83479e72003-06-25 16:12:37 +0000780 if (cpu_single_env)
781 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000782#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000783 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000784 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000785#endif
bellard25eb4482003-05-14 21:50:54 +0000786 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000787 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000788 return 1;
789 }
bellardfbf9eeb2004-04-25 21:21:33 +0000790
bellard3fb2ded2003-06-24 13:22:59 +0000791 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000792 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000793 if (ret < 0)
794 return 0; /* not an MMU fault */
795 if (ret == 0)
796 return 1; /* the MMU fault was handled without causing real CPU fault */
797 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000798 tb = tb_find_pc(pc);
799 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000800 /* the PC is inside the translated code. It means that we have
801 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000802 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000803 }
bellard4cbf74b2003-08-10 21:48:43 +0000804 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000805#if 0
ths5fafdf22007-09-16 21:08:06 +0000806 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000807 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000808#endif
bellard4cbf74b2003-08-10 21:48:43 +0000809 /* we restore the process signal mask as the sigreturn should
810 do it (XXX: use sigsetjmp) */
811 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000812 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000813 } else {
814 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000815 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000816 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000817 }
bellard3fb2ded2003-06-24 13:22:59 +0000818 /* never comes here */
819 return 1;
820}
821
bellarde4533c72003-06-15 19:51:39 +0000822#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000823static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000824 int is_write, sigset_t *old_set,
825 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000826{
bellard68016c62005-02-07 23:12:27 +0000827 TranslationBlock *tb;
828 int ret;
829
830 if (cpu_single_env)
831 env = cpu_single_env; /* XXX: find a correct solution for multithread */
832#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000833 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000834 pc, address, is_write, *(unsigned long *)old_set);
835#endif
bellard9f0777e2005-02-02 20:42:01 +0000836 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000837 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000838 return 1;
839 }
bellard68016c62005-02-07 23:12:27 +0000840 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000841 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000842 if (ret < 0)
843 return 0; /* not an MMU fault */
844 if (ret == 0)
845 return 1; /* the MMU fault was handled without causing real CPU fault */
846 /* now we have a real cpu fault */
847 tb = tb_find_pc(pc);
848 if (tb) {
849 /* the PC is inside the translated code. It means that we have
850 a virtual CPU fault */
851 cpu_restore_state(tb, env, pc, puc);
852 }
853 /* we restore the process signal mask as the sigreturn should
854 do it (XXX: use sigsetjmp) */
855 sigprocmask(SIG_SETMASK, old_set, NULL);
856 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000857}
bellard93ac68b2003-09-30 20:57:29 +0000858#elif defined(TARGET_SPARC)
859static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000860 int is_write, sigset_t *old_set,
861 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000862{
bellard68016c62005-02-07 23:12:27 +0000863 TranslationBlock *tb;
864 int ret;
865
866 if (cpu_single_env)
867 env = cpu_single_env; /* XXX: find a correct solution for multithread */
868#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000869 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000870 pc, address, is_write, *(unsigned long *)old_set);
871#endif
bellardb453b702004-01-04 15:45:21 +0000872 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000873 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000874 return 1;
875 }
bellard68016c62005-02-07 23:12:27 +0000876 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000877 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000878 if (ret < 0)
879 return 0; /* not an MMU fault */
880 if (ret == 0)
881 return 1; /* the MMU fault was handled without causing real CPU fault */
882 /* now we have a real cpu fault */
883 tb = tb_find_pc(pc);
884 if (tb) {
885 /* the PC is inside the translated code. It means that we have
886 a virtual CPU fault */
887 cpu_restore_state(tb, env, pc, puc);
888 }
889 /* we restore the process signal mask as the sigreturn should
890 do it (XXX: use sigsetjmp) */
891 sigprocmask(SIG_SETMASK, old_set, NULL);
892 cpu_loop_exit();
bellard93ac68b2003-09-30 20:57:29 +0000893}
bellard67867302003-11-23 17:05:30 +0000894#elif defined (TARGET_PPC)
895static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000896 int is_write, sigset_t *old_set,
897 void *puc)
bellard67867302003-11-23 17:05:30 +0000898{
899 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000900 int ret;
ths3b46e622007-09-17 08:09:54 +0000901
bellard67867302003-11-23 17:05:30 +0000902 if (cpu_single_env)
903 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000904#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000905 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000906 pc, address, is_write, *(unsigned long *)old_set);
907#endif
908 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000909 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000910 return 1;
911 }
912
bellardce097762004-01-04 23:53:18 +0000913 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000914 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000915 if (ret < 0)
916 return 0; /* not an MMU fault */
917 if (ret == 0)
918 return 1; /* the MMU fault was handled without causing real CPU fault */
919
bellard67867302003-11-23 17:05:30 +0000920 /* now we have a real cpu fault */
921 tb = tb_find_pc(pc);
922 if (tb) {
923 /* the PC is inside the translated code. It means that we have
924 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000925 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000926 }
bellardce097762004-01-04 23:53:18 +0000927 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000928#if 0
ths5fafdf22007-09-16 21:08:06 +0000929 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000930 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000931#endif
932 /* we restore the process signal mask as the sigreturn should
933 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000934 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000935 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000936 } else {
937 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000938 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000939 }
bellard67867302003-11-23 17:05:30 +0000940 /* never comes here */
941 return 1;
942}
bellard6af0bf92005-07-02 14:58:51 +0000943
pbrooke6e59062006-10-22 00:18:54 +0000944#elif defined(TARGET_M68K)
945static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
946 int is_write, sigset_t *old_set,
947 void *puc)
948{
949 TranslationBlock *tb;
950 int ret;
951
952 if (cpu_single_env)
953 env = cpu_single_env; /* XXX: find a correct solution for multithread */
954#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000955 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000956 pc, address, is_write, *(unsigned long *)old_set);
957#endif
958 /* XXX: locking issue */
959 if (is_write && page_unprotect(address, pc, puc)) {
960 return 1;
961 }
962 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000963 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000964 if (ret < 0)
965 return 0; /* not an MMU fault */
966 if (ret == 0)
967 return 1; /* the MMU fault was handled without causing real CPU fault */
968 /* now we have a real cpu fault */
969 tb = tb_find_pc(pc);
970 if (tb) {
971 /* the PC is inside the translated code. It means that we have
972 a virtual CPU fault */
973 cpu_restore_state(tb, env, pc, puc);
974 }
975 /* we restore the process signal mask as the sigreturn should
976 do it (XXX: use sigsetjmp) */
977 sigprocmask(SIG_SETMASK, old_set, NULL);
978 cpu_loop_exit();
979 /* never comes here */
980 return 1;
981}
982
bellard6af0bf92005-07-02 14:58:51 +0000983#elif defined (TARGET_MIPS)
984static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
985 int is_write, sigset_t *old_set,
986 void *puc)
987{
988 TranslationBlock *tb;
989 int ret;
ths3b46e622007-09-17 08:09:54 +0000990
bellard6af0bf92005-07-02 14:58:51 +0000991 if (cpu_single_env)
992 env = cpu_single_env; /* XXX: find a correct solution for multithread */
993#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000994 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000995 pc, address, is_write, *(unsigned long *)old_set);
996#endif
997 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000998 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000999 return 1;
1000 }
1001
1002 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001003 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001004 if (ret < 0)
1005 return 0; /* not an MMU fault */
1006 if (ret == 0)
1007 return 1; /* the MMU fault was handled without causing real CPU fault */
1008
1009 /* now we have a real cpu fault */
1010 tb = tb_find_pc(pc);
1011 if (tb) {
1012 /* the PC is inside the translated code. It means that we have
1013 a virtual CPU fault */
1014 cpu_restore_state(tb, env, pc, puc);
1015 }
1016 if (ret == 1) {
1017#if 0
ths5fafdf22007-09-16 21:08:06 +00001018 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001019 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001020#endif
1021 /* we restore the process signal mask as the sigreturn should
1022 do it (XXX: use sigsetjmp) */
1023 sigprocmask(SIG_SETMASK, old_set, NULL);
1024 do_raise_exception_err(env->exception_index, env->error_code);
1025 } else {
1026 /* activate soft MMU for this block */
1027 cpu_resume_from_signal(env, puc);
1028 }
1029 /* never comes here */
1030 return 1;
1031}
1032
bellardfdf9b3e2006-04-27 21:07:38 +00001033#elif defined (TARGET_SH4)
1034static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1035 int is_write, sigset_t *old_set,
1036 void *puc)
1037{
1038 TranslationBlock *tb;
1039 int ret;
ths3b46e622007-09-17 08:09:54 +00001040
bellardfdf9b3e2006-04-27 21:07:38 +00001041 if (cpu_single_env)
1042 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1043#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001044 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001045 pc, address, is_write, *(unsigned long *)old_set);
1046#endif
1047 /* XXX: locking issue */
1048 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1049 return 1;
1050 }
1051
1052 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001053 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001054 if (ret < 0)
1055 return 0; /* not an MMU fault */
1056 if (ret == 0)
1057 return 1; /* the MMU fault was handled without causing real CPU fault */
1058
1059 /* now we have a real cpu fault */
1060 tb = tb_find_pc(pc);
1061 if (tb) {
1062 /* the PC is inside the translated code. It means that we have
1063 a virtual CPU fault */
1064 cpu_restore_state(tb, env, pc, puc);
1065 }
bellardfdf9b3e2006-04-27 21:07:38 +00001066#if 0
ths5fafdf22007-09-16 21:08:06 +00001067 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001068 env->nip, env->error_code, tb);
1069#endif
1070 /* we restore the process signal mask as the sigreturn should
1071 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001072 sigprocmask(SIG_SETMASK, old_set, NULL);
1073 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001074 /* never comes here */
1075 return 1;
1076}
j_mayereddf68a2007-04-05 07:22:49 +00001077
1078#elif defined (TARGET_ALPHA)
1079static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1080 int is_write, sigset_t *old_set,
1081 void *puc)
1082{
1083 TranslationBlock *tb;
1084 int ret;
ths3b46e622007-09-17 08:09:54 +00001085
j_mayereddf68a2007-04-05 07:22:49 +00001086 if (cpu_single_env)
1087 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1088#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001089 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001090 pc, address, is_write, *(unsigned long *)old_set);
1091#endif
1092 /* XXX: locking issue */
1093 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1094 return 1;
1095 }
1096
1097 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001098 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001099 if (ret < 0)
1100 return 0; /* not an MMU fault */
1101 if (ret == 0)
1102 return 1; /* the MMU fault was handled without causing real CPU fault */
1103
1104 /* now we have a real cpu fault */
1105 tb = tb_find_pc(pc);
1106 if (tb) {
1107 /* the PC is inside the translated code. It means that we have
1108 a virtual CPU fault */
1109 cpu_restore_state(tb, env, pc, puc);
1110 }
1111#if 0
ths5fafdf22007-09-16 21:08:06 +00001112 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001113 env->nip, env->error_code, tb);
1114#endif
1115 /* we restore the process signal mask as the sigreturn should
1116 do it (XXX: use sigsetjmp) */
1117 sigprocmask(SIG_SETMASK, old_set, NULL);
1118 cpu_loop_exit();
1119 /* never comes here */
1120 return 1;
1121}
thsf1ccf902007-10-08 13:16:14 +00001122#elif defined (TARGET_CRIS)
1123static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1124 int is_write, sigset_t *old_set,
1125 void *puc)
1126{
1127 TranslationBlock *tb;
1128 int ret;
1129
1130 if (cpu_single_env)
1131 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1132#if defined(DEBUG_SIGNAL)
1133 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1134 pc, address, is_write, *(unsigned long *)old_set);
1135#endif
1136 /* XXX: locking issue */
1137 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1138 return 1;
1139 }
1140
1141 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001142 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001143 if (ret < 0)
1144 return 0; /* not an MMU fault */
1145 if (ret == 0)
1146 return 1; /* the MMU fault was handled without causing real CPU fault */
1147
1148 /* now we have a real cpu fault */
1149 tb = tb_find_pc(pc);
1150 if (tb) {
1151 /* the PC is inside the translated code. It means that we have
1152 a virtual CPU fault */
1153 cpu_restore_state(tb, env, pc, puc);
1154 }
1155#if 0
1156 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1157 env->nip, env->error_code, tb);
1158#endif
1159 /* we restore the process signal mask as the sigreturn should
1160 do it (XXX: use sigsetjmp) */
1161 sigprocmask(SIG_SETMASK, old_set, NULL);
1162 cpu_loop_exit();
1163 /* never comes here */
1164 return 1;
1165}
1166
bellarde4533c72003-06-15 19:51:39 +00001167#else
1168#error unsupported target CPU
1169#endif
bellard9de5e442003-03-23 16:49:39 +00001170
bellard2b413142003-05-14 23:01:10 +00001171#if defined(__i386__)
1172
bellardd8ecc0b2007-02-05 21:41:46 +00001173#if defined(__APPLE__)
1174# include <sys/ucontext.h>
1175
1176# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1177# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1178# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1179#else
1180# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1181# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1182# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1183#endif
1184
ths5fafdf22007-09-16 21:08:06 +00001185int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001186 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001187{
ths5a7b5422007-01-31 12:16:51 +00001188 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001189 struct ucontext *uc = puc;
1190 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001191 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001192
bellardd691f662003-03-24 21:58:34 +00001193#ifndef REG_EIP
1194/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001195#define REG_EIP EIP
1196#define REG_ERR ERR
1197#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001198#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001199 pc = EIP_sig(uc);
1200 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001201 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1202 trapno == 0xe ?
1203 (ERROR_sig(uc) >> 1) & 1 : 0,
1204 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001205}
1206
bellardbc51c5c2004-03-17 23:46:04 +00001207#elif defined(__x86_64__)
1208
ths5a7b5422007-01-31 12:16:51 +00001209int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001210 void *puc)
1211{
ths5a7b5422007-01-31 12:16:51 +00001212 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001213 struct ucontext *uc = puc;
1214 unsigned long pc;
1215
1216 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001217 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1218 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001219 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1220 &uc->uc_sigmask, puc);
1221}
1222
bellard83fb7ad2004-07-05 21:25:26 +00001223#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001224
bellard83fb7ad2004-07-05 21:25:26 +00001225/***********************************************************************
1226 * signal context platform-specific definitions
1227 * From Wine
1228 */
1229#ifdef linux
1230/* All Registers access - only for local access */
1231# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1232/* Gpr Registers access */
1233# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1234# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1235# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1236# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1237# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1238# define LR_sig(context) REG_sig(link, context) /* Link register */
1239# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1240/* Float Registers access */
1241# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1242# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1243/* Exception Registers access */
1244# define DAR_sig(context) REG_sig(dar, context)
1245# define DSISR_sig(context) REG_sig(dsisr, context)
1246# define TRAP_sig(context) REG_sig(trap, context)
1247#endif /* linux */
1248
1249#ifdef __APPLE__
1250# include <sys/ucontext.h>
1251typedef struct ucontext SIGCONTEXT;
1252/* All Registers access - only for local access */
1253# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1254# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1255# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1256# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1257/* Gpr Registers access */
1258# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1259# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1260# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1261# define CTR_sig(context) REG_sig(ctr, context)
1262# define XER_sig(context) REG_sig(xer, context) /* Link register */
1263# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1264# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1265/* Float Registers access */
1266# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1267# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1268/* Exception Registers access */
1269# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1270# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1271# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1272#endif /* __APPLE__ */
1273
ths5fafdf22007-09-16 21:08:06 +00001274int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001275 void *puc)
bellard2b413142003-05-14 23:01:10 +00001276{
ths5a7b5422007-01-31 12:16:51 +00001277 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001278 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001279 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001280 int is_write;
1281
bellard83fb7ad2004-07-05 21:25:26 +00001282 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001283 is_write = 0;
1284#if 0
1285 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001286 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001287 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001288#else
bellard83fb7ad2004-07-05 21:25:26 +00001289 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001290 is_write = 1;
1291#endif
ths5fafdf22007-09-16 21:08:06 +00001292 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001293 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001294}
bellard2b413142003-05-14 23:01:10 +00001295
bellard2f87c602003-06-02 20:38:09 +00001296#elif defined(__alpha__)
1297
ths5fafdf22007-09-16 21:08:06 +00001298int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001299 void *puc)
1300{
ths5a7b5422007-01-31 12:16:51 +00001301 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001302 struct ucontext *uc = puc;
1303 uint32_t *pc = uc->uc_mcontext.sc_pc;
1304 uint32_t insn = *pc;
1305 int is_write = 0;
1306
bellard8c6939c2003-06-09 15:28:00 +00001307 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001308 switch (insn >> 26) {
1309 case 0x0d: // stw
1310 case 0x0e: // stb
1311 case 0x0f: // stq_u
1312 case 0x24: // stf
1313 case 0x25: // stg
1314 case 0x26: // sts
1315 case 0x27: // stt
1316 case 0x2c: // stl
1317 case 0x2d: // stq
1318 case 0x2e: // stl_c
1319 case 0x2f: // stq_c
1320 is_write = 1;
1321 }
1322
ths5fafdf22007-09-16 21:08:06 +00001323 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001324 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001325}
bellard8c6939c2003-06-09 15:28:00 +00001326#elif defined(__sparc__)
1327
ths5fafdf22007-09-16 21:08:06 +00001328int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001329 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001330{
ths5a7b5422007-01-31 12:16:51 +00001331 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001332 uint32_t *regs = (uint32_t *)(info + 1);
1333 void *sigmask = (regs + 20);
1334 unsigned long pc;
1335 int is_write;
1336 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001337
bellard8c6939c2003-06-09 15:28:00 +00001338 /* XXX: is there a standard glibc define ? */
1339 pc = regs[1];
1340 /* XXX: need kernel patch to get write flag faster */
1341 is_write = 0;
1342 insn = *(uint32_t *)pc;
1343 if ((insn >> 30) == 3) {
1344 switch((insn >> 19) & 0x3f) {
1345 case 0x05: // stb
1346 case 0x06: // sth
1347 case 0x04: // st
1348 case 0x07: // std
1349 case 0x24: // stf
1350 case 0x27: // stdf
1351 case 0x25: // stfsr
1352 is_write = 1;
1353 break;
1354 }
1355 }
ths5fafdf22007-09-16 21:08:06 +00001356 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001357 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001358}
1359
1360#elif defined(__arm__)
1361
ths5fafdf22007-09-16 21:08:06 +00001362int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001363 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001364{
ths5a7b5422007-01-31 12:16:51 +00001365 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001366 struct ucontext *uc = puc;
1367 unsigned long pc;
1368 int is_write;
ths3b46e622007-09-17 08:09:54 +00001369
bellard8c6939c2003-06-09 15:28:00 +00001370 pc = uc->uc_mcontext.gregs[R15];
1371 /* XXX: compute is_write */
1372 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001373 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001374 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001375 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001376}
1377
bellard38e584a2003-08-10 22:14:22 +00001378#elif defined(__mc68000)
1379
ths5fafdf22007-09-16 21:08:06 +00001380int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001381 void *puc)
1382{
ths5a7b5422007-01-31 12:16:51 +00001383 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001384 struct ucontext *uc = puc;
1385 unsigned long pc;
1386 int is_write;
ths3b46e622007-09-17 08:09:54 +00001387
bellard38e584a2003-08-10 22:14:22 +00001388 pc = uc->uc_mcontext.gregs[16];
1389 /* XXX: compute is_write */
1390 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001391 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001392 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001393 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001394}
1395
bellardb8076a72005-04-07 22:20:31 +00001396#elif defined(__ia64)
1397
1398#ifndef __ISR_VALID
1399 /* This ought to be in <bits/siginfo.h>... */
1400# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001401#endif
1402
ths5a7b5422007-01-31 12:16:51 +00001403int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001404{
ths5a7b5422007-01-31 12:16:51 +00001405 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001406 struct ucontext *uc = puc;
1407 unsigned long ip;
1408 int is_write = 0;
1409
1410 ip = uc->uc_mcontext.sc_ip;
1411 switch (host_signum) {
1412 case SIGILL:
1413 case SIGFPE:
1414 case SIGSEGV:
1415 case SIGBUS:
1416 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001417 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001418 /* ISR.W (write-access) is bit 33: */
1419 is_write = (info->si_isr >> 33) & 1;
1420 break;
1421
1422 default:
1423 break;
1424 }
1425 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1426 is_write,
1427 &uc->uc_sigmask, puc);
1428}
1429
bellard90cb9492005-07-24 15:11:38 +00001430#elif defined(__s390__)
1431
ths5fafdf22007-09-16 21:08:06 +00001432int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001433 void *puc)
1434{
ths5a7b5422007-01-31 12:16:51 +00001435 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001436 struct ucontext *uc = puc;
1437 unsigned long pc;
1438 int is_write;
ths3b46e622007-09-17 08:09:54 +00001439
bellard90cb9492005-07-24 15:11:38 +00001440 pc = uc->uc_mcontext.psw.addr;
1441 /* XXX: compute is_write */
1442 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001443 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001444 is_write, &uc->uc_sigmask, puc);
1445}
1446
1447#elif defined(__mips__)
1448
ths5fafdf22007-09-16 21:08:06 +00001449int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001450 void *puc)
1451{
ths9617efe2007-05-08 21:05:55 +00001452 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001453 struct ucontext *uc = puc;
1454 greg_t pc = uc->uc_mcontext.pc;
1455 int is_write;
ths3b46e622007-09-17 08:09:54 +00001456
thsc4b89d12007-05-05 19:23:11 +00001457 /* XXX: compute is_write */
1458 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001459 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001460 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001461}
1462
bellard2b413142003-05-14 23:01:10 +00001463#else
1464
bellard3fb2ded2003-06-24 13:22:59 +00001465#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001466
1467#endif
bellard67b915a2004-03-31 23:37:16 +00001468
1469#endif /* !defined(CONFIG_SOFTMMU) */