blob: e8b93a832e25e763329646ef7aad0590c3b6ff8d [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)
514 /* XXXXX */
j_mayereddf68a2007-04-05 07:22:49 +0000515#elif defined(TARGET_ALPHA)
516 if (interrupt_request & CPU_INTERRUPT_HARD) {
517 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000518 BREAK_CHAIN;
j_mayereddf68a2007-04-05 07:22:49 +0000519 }
thsf1ccf902007-10-08 13:16:14 +0000520#elif defined(TARGET_CRIS)
521 if (interrupt_request & CPU_INTERRUPT_HARD) {
522 do_interrupt(env);
523 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
pbrook497ad682007-11-23 02:11:10 +0000524 BREAK_CHAIN;
thsf1ccf902007-10-08 13:16:14 +0000525 }
pbrook06338792007-05-23 19:58:11 +0000526#elif defined(TARGET_M68K)
527 if (interrupt_request & CPU_INTERRUPT_HARD
528 && ((env->sr & SR_I) >> SR_I_SHIFT)
529 < env->pending_level) {
530 /* Real hardware gets the interrupt vector via an
531 IACK cycle at this point. Current emulated
532 hardware doesn't rely on this, so we
533 provide/save the vector when the interrupt is
534 first signalled. */
535 env->exception_index = env->pending_vector;
536 do_interrupt(1);
pbrook497ad682007-11-23 02:11:10 +0000537 BREAK_CHAIN;
pbrook06338792007-05-23 19:58:11 +0000538 }
bellard68a79312003-06-30 13:12:32 +0000539#endif
bellard9d050952006-05-22 22:03:52 +0000540 /* Don't use the cached interupt_request value,
541 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000542 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000543 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
544 /* ensure that no TB jump will be modified as
545 the program flow was changed */
pbrook497ad682007-11-23 02:11:10 +0000546 BREAK_CHAIN;
bellardbf3e8bf2004-02-16 21:58:54 +0000547 }
bellard68a79312003-06-30 13:12:32 +0000548 if (interrupt_request & CPU_INTERRUPT_EXIT) {
549 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
550 env->exception_index = EXCP_INTERRUPT;
551 cpu_loop_exit();
552 }
bellard3fb2ded2003-06-24 13:22:59 +0000553 }
554#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000555 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000556 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000557 regs_to_env();
558#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000559 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000560 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000561 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000562#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000563 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000564#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000565 REGWPTR = env->regbase + (env->cwp * 16);
566 env->regwptr = REGWPTR;
567 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000568#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000569 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000570#elif defined(TARGET_M68K)
571 cpu_m68k_flush_flags(env, env->cc_op);
572 env->cc_op = CC_OP_FLAGS;
573 env->sr = (env->sr & 0xffe0)
574 | env->cc_dest | (env->cc_x << 4);
575 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000576#elif defined(TARGET_MIPS)
577 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000578#elif defined(TARGET_SH4)
579 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000580#elif defined(TARGET_ALPHA)
581 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000582#elif defined(TARGET_CRIS)
583 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000584#else
ths5fafdf22007-09-16 21:08:06 +0000585#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000586#endif
bellard3fb2ded2003-06-24 13:22:59 +0000587 }
bellard7d132992003-03-06 23:23:54 +0000588#endif
bellard8a40a182005-11-20 10:35:40 +0000589 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000590#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000591 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000592 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
593 (long)tb->tc_ptr, tb->pc,
594 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000595 }
bellard9d27abd2003-05-10 13:13:54 +0000596#endif
bellardfdbb4692006-06-14 17:32:25 +0000597#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard3fb2ded2003-06-24 13:22:59 +0000598 T0 = tmp_T0;
ths3b46e622007-09-17 08:09:54 +0000599#endif
bellard8a40a182005-11-20 10:35:40 +0000600 /* see if we can patch the calling TB. When the TB
601 spans two pages, we cannot safely do a direct
602 jump. */
bellardc27004e2005-01-03 23:35:10 +0000603 {
bellard8a40a182005-11-20 10:35:40 +0000604 if (T0 != 0 &&
bellardf32fc642006-02-08 22:43:39 +0000605#if USE_KQEMU
606 (env->kqemu_enabled != 2) &&
607#endif
bellardec6338b2007-11-08 14:25:03 +0000608 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000609 spin_lock(&tb_lock);
bellardc27004e2005-01-03 23:35:10 +0000610 tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000611 spin_unlock(&tb_lock);
612 }
bellardc27004e2005-01-03 23:35:10 +0000613 }
bellard3fb2ded2003-06-24 13:22:59 +0000614 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000615 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000616 /* execute the generated code */
617 gen_func = (void *)tc_ptr;
618#if defined(__sparc__)
619 __asm__ __volatile__("call %0\n\t"
620 "mov %%o7,%%i0"
621 : /* no outputs */
ths5fafdf22007-09-16 21:08:06 +0000622 : "r" (gen_func)
bellardfdbb4692006-06-14 17:32:25 +0000623 : "i0", "i1", "i2", "i3", "i4", "i5",
thsfaab7592007-03-19 20:39:49 +0000624 "o0", "o1", "o2", "o3", "o4", "o5",
bellardfdbb4692006-06-14 17:32:25 +0000625 "l0", "l1", "l2", "l3", "l4", "l5",
626 "l6", "l7");
bellard3fb2ded2003-06-24 13:22:59 +0000627#elif defined(__arm__)
628 asm volatile ("mov pc, %0\n\t"
629 ".global exec_loop\n\t"
630 "exec_loop:\n\t"
631 : /* no outputs */
632 : "r" (gen_func)
633 : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
bellardb8076a72005-04-07 22:20:31 +0000634#elif defined(__ia64)
635 struct fptr {
636 void *ip;
637 void *gp;
638 } fp;
639
640 fp.ip = tc_ptr;
641 fp.gp = code_gen_buffer + 2 * (1 << 20);
642 (*(void (*)(void)) &fp)();
bellard3fb2ded2003-06-24 13:22:59 +0000643#else
644 gen_func();
645#endif
bellard83479e72003-06-25 16:12:37 +0000646 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000647 /* reset soft MMU for next block (it can currently
648 only be set by a memory fault) */
649#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000650 if (env->hflags & HF_SOFTMMU_MASK) {
651 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000652 /* do not allow linking to another block */
653 T0 = 0;
654 }
655#endif
bellardf32fc642006-02-08 22:43:39 +0000656#if defined(USE_KQEMU)
657#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
658 if (kqemu_is_ok(env) &&
659 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
660 cpu_loop_exit();
661 }
662#endif
ths50a518e2007-06-03 18:52:15 +0000663 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000664 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000665 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000666 }
bellard3fb2ded2003-06-24 13:22:59 +0000667 } /* for(;;) */
668
bellard7d132992003-03-06 23:23:54 +0000669
bellarde4533c72003-06-15 19:51:39 +0000670#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000671 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000672 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000673#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000674 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000675#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000676#if defined(reg_REGWPTR)
677 REGWPTR = saved_regwptr;
678#endif
bellard67867302003-11-23 17:05:30 +0000679#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000680#elif defined(TARGET_M68K)
681 cpu_m68k_flush_flags(env, env->cc_op);
682 env->cc_op = CC_OP_FLAGS;
683 env->sr = (env->sr & 0xffe0)
684 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000685#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000686#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000687#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000688#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000689 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000690#else
691#error unsupported target CPU
692#endif
pbrook1057eaa2007-02-04 13:37:44 +0000693
694 /* restore global registers */
bellardfdbb4692006-06-14 17:32:25 +0000695#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard8c6939c2003-06-09 15:28:00 +0000696 asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
697#endif
pbrook1057eaa2007-02-04 13:37:44 +0000698#include "hostregs_helper.h"
699
bellard6a00d602005-11-21 23:25:50 +0000700 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000701 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000702 return ret;
703}
bellard6dbad632003-03-16 18:05:05 +0000704
bellardfbf9eeb2004-04-25 21:21:33 +0000705/* must only be called from the generated code as an exception can be
706 generated */
707void tb_invalidate_page_range(target_ulong start, target_ulong end)
708{
bellarddc5d0b32004-06-22 18:43:30 +0000709 /* XXX: cannot enable it yet because it yields to MMU exception
710 where NIP != read address on PowerPC */
711#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000712 target_ulong phys_addr;
713 phys_addr = get_phys_addr_code(env, start);
714 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000715#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000716}
717
bellard1a18c712003-10-30 01:07:51 +0000718#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000719
bellard6dbad632003-03-16 18:05:05 +0000720void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
721{
722 CPUX86State *saved_env;
723
724 saved_env = env;
725 env = s;
bellarda412ac52003-07-26 18:01:40 +0000726 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000727 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000728 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000729 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000730 } else {
bellardb453b702004-01-04 15:45:21 +0000731 load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000732 }
bellard6dbad632003-03-16 18:05:05 +0000733 env = saved_env;
734}
bellard9de5e442003-03-23 16:49:39 +0000735
bellard6f12a2a2007-11-11 22:16:56 +0000736void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000737{
738 CPUX86State *saved_env;
739
740 saved_env = env;
741 env = s;
ths3b46e622007-09-17 08:09:54 +0000742
bellard6f12a2a2007-11-11 22:16:56 +0000743 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000744
745 env = saved_env;
746}
747
bellard6f12a2a2007-11-11 22:16:56 +0000748void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000749{
750 CPUX86State *saved_env;
751
752 saved_env = env;
753 env = s;
ths3b46e622007-09-17 08:09:54 +0000754
bellard6f12a2a2007-11-11 22:16:56 +0000755 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000756
757 env = saved_env;
758}
759
bellarde4533c72003-06-15 19:51:39 +0000760#endif /* TARGET_I386 */
761
bellard67b915a2004-03-31 23:37:16 +0000762#if !defined(CONFIG_SOFTMMU)
763
bellard3fb2ded2003-06-24 13:22:59 +0000764#if defined(TARGET_I386)
765
bellardb56dad12003-05-08 15:38:04 +0000766/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000767 the effective address of the memory exception. 'is_write' is 1 if a
768 write caused the exception and otherwise 0'. 'old_set' is the
769 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000770static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000771 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000772 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000773{
bellarda513fe12003-05-27 23:29:48 +0000774 TranslationBlock *tb;
775 int ret;
bellard68a79312003-06-30 13:12:32 +0000776
bellard83479e72003-06-25 16:12:37 +0000777 if (cpu_single_env)
778 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000779#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000780 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000781 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000782#endif
bellard25eb4482003-05-14 21:50:54 +0000783 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000784 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000785 return 1;
786 }
bellardfbf9eeb2004-04-25 21:21:33 +0000787
bellard3fb2ded2003-06-24 13:22:59 +0000788 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000789 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000790 if (ret < 0)
791 return 0; /* not an MMU fault */
792 if (ret == 0)
793 return 1; /* the MMU fault was handled without causing real CPU fault */
794 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000795 tb = tb_find_pc(pc);
796 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000797 /* the PC is inside the translated code. It means that we have
798 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000799 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000800 }
bellard4cbf74b2003-08-10 21:48:43 +0000801 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000802#if 0
ths5fafdf22007-09-16 21:08:06 +0000803 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000804 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000805#endif
bellard4cbf74b2003-08-10 21:48:43 +0000806 /* we restore the process signal mask as the sigreturn should
807 do it (XXX: use sigsetjmp) */
808 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000809 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000810 } else {
811 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000812 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000813 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000814 }
bellard3fb2ded2003-06-24 13:22:59 +0000815 /* never comes here */
816 return 1;
817}
818
bellarde4533c72003-06-15 19:51:39 +0000819#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000820static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000821 int is_write, sigset_t *old_set,
822 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000823{
bellard68016c62005-02-07 23:12:27 +0000824 TranslationBlock *tb;
825 int ret;
826
827 if (cpu_single_env)
828 env = cpu_single_env; /* XXX: find a correct solution for multithread */
829#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000830 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000831 pc, address, is_write, *(unsigned long *)old_set);
832#endif
bellard9f0777e2005-02-02 20:42:01 +0000833 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000834 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000835 return 1;
836 }
bellard68016c62005-02-07 23:12:27 +0000837 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000838 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000839 if (ret < 0)
840 return 0; /* not an MMU fault */
841 if (ret == 0)
842 return 1; /* the MMU fault was handled without causing real CPU fault */
843 /* now we have a real cpu fault */
844 tb = tb_find_pc(pc);
845 if (tb) {
846 /* the PC is inside the translated code. It means that we have
847 a virtual CPU fault */
848 cpu_restore_state(tb, env, pc, puc);
849 }
850 /* we restore the process signal mask as the sigreturn should
851 do it (XXX: use sigsetjmp) */
852 sigprocmask(SIG_SETMASK, old_set, NULL);
853 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000854}
bellard93ac68b2003-09-30 20:57:29 +0000855#elif defined(TARGET_SPARC)
856static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000857 int is_write, sigset_t *old_set,
858 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000859{
bellard68016c62005-02-07 23:12:27 +0000860 TranslationBlock *tb;
861 int ret;
862
863 if (cpu_single_env)
864 env = cpu_single_env; /* XXX: find a correct solution for multithread */
865#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000866 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000867 pc, address, is_write, *(unsigned long *)old_set);
868#endif
bellardb453b702004-01-04 15:45:21 +0000869 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000870 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000871 return 1;
872 }
bellard68016c62005-02-07 23:12:27 +0000873 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000874 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000875 if (ret < 0)
876 return 0; /* not an MMU fault */
877 if (ret == 0)
878 return 1; /* the MMU fault was handled without causing real CPU fault */
879 /* now we have a real cpu fault */
880 tb = tb_find_pc(pc);
881 if (tb) {
882 /* the PC is inside the translated code. It means that we have
883 a virtual CPU fault */
884 cpu_restore_state(tb, env, pc, puc);
885 }
886 /* we restore the process signal mask as the sigreturn should
887 do it (XXX: use sigsetjmp) */
888 sigprocmask(SIG_SETMASK, old_set, NULL);
889 cpu_loop_exit();
bellard93ac68b2003-09-30 20:57:29 +0000890}
bellard67867302003-11-23 17:05:30 +0000891#elif defined (TARGET_PPC)
892static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000893 int is_write, sigset_t *old_set,
894 void *puc)
bellard67867302003-11-23 17:05:30 +0000895{
896 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000897 int ret;
ths3b46e622007-09-17 08:09:54 +0000898
bellard67867302003-11-23 17:05:30 +0000899 if (cpu_single_env)
900 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000901#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000902 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000903 pc, address, is_write, *(unsigned long *)old_set);
904#endif
905 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000906 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000907 return 1;
908 }
909
bellardce097762004-01-04 23:53:18 +0000910 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000911 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000912 if (ret < 0)
913 return 0; /* not an MMU fault */
914 if (ret == 0)
915 return 1; /* the MMU fault was handled without causing real CPU fault */
916
bellard67867302003-11-23 17:05:30 +0000917 /* now we have a real cpu fault */
918 tb = tb_find_pc(pc);
919 if (tb) {
920 /* the PC is inside the translated code. It means that we have
921 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000922 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000923 }
bellardce097762004-01-04 23:53:18 +0000924 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000925#if 0
ths5fafdf22007-09-16 21:08:06 +0000926 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000927 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000928#endif
929 /* we restore the process signal mask as the sigreturn should
930 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000931 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000932 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000933 } else {
934 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000935 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000936 }
bellard67867302003-11-23 17:05:30 +0000937 /* never comes here */
938 return 1;
939}
bellard6af0bf92005-07-02 14:58:51 +0000940
pbrooke6e59062006-10-22 00:18:54 +0000941#elif defined(TARGET_M68K)
942static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
943 int is_write, sigset_t *old_set,
944 void *puc)
945{
946 TranslationBlock *tb;
947 int ret;
948
949 if (cpu_single_env)
950 env = cpu_single_env; /* XXX: find a correct solution for multithread */
951#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000952 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000953 pc, address, is_write, *(unsigned long *)old_set);
954#endif
955 /* XXX: locking issue */
956 if (is_write && page_unprotect(address, pc, puc)) {
957 return 1;
958 }
959 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000960 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000961 if (ret < 0)
962 return 0; /* not an MMU fault */
963 if (ret == 0)
964 return 1; /* the MMU fault was handled without causing real CPU fault */
965 /* now we have a real cpu fault */
966 tb = tb_find_pc(pc);
967 if (tb) {
968 /* the PC is inside the translated code. It means that we have
969 a virtual CPU fault */
970 cpu_restore_state(tb, env, pc, puc);
971 }
972 /* we restore the process signal mask as the sigreturn should
973 do it (XXX: use sigsetjmp) */
974 sigprocmask(SIG_SETMASK, old_set, NULL);
975 cpu_loop_exit();
976 /* never comes here */
977 return 1;
978}
979
bellard6af0bf92005-07-02 14:58:51 +0000980#elif defined (TARGET_MIPS)
981static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
982 int is_write, sigset_t *old_set,
983 void *puc)
984{
985 TranslationBlock *tb;
986 int ret;
ths3b46e622007-09-17 08:09:54 +0000987
bellard6af0bf92005-07-02 14:58:51 +0000988 if (cpu_single_env)
989 env = cpu_single_env; /* XXX: find a correct solution for multithread */
990#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000991 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000992 pc, address, is_write, *(unsigned long *)old_set);
993#endif
994 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000995 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000996 return 1;
997 }
998
999 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001000 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001001 if (ret < 0)
1002 return 0; /* not an MMU fault */
1003 if (ret == 0)
1004 return 1; /* the MMU fault was handled without causing real CPU fault */
1005
1006 /* now we have a real cpu fault */
1007 tb = tb_find_pc(pc);
1008 if (tb) {
1009 /* the PC is inside the translated code. It means that we have
1010 a virtual CPU fault */
1011 cpu_restore_state(tb, env, pc, puc);
1012 }
1013 if (ret == 1) {
1014#if 0
ths5fafdf22007-09-16 21:08:06 +00001015 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001016 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001017#endif
1018 /* we restore the process signal mask as the sigreturn should
1019 do it (XXX: use sigsetjmp) */
1020 sigprocmask(SIG_SETMASK, old_set, NULL);
1021 do_raise_exception_err(env->exception_index, env->error_code);
1022 } else {
1023 /* activate soft MMU for this block */
1024 cpu_resume_from_signal(env, puc);
1025 }
1026 /* never comes here */
1027 return 1;
1028}
1029
bellardfdf9b3e2006-04-27 21:07:38 +00001030#elif defined (TARGET_SH4)
1031static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1032 int is_write, sigset_t *old_set,
1033 void *puc)
1034{
1035 TranslationBlock *tb;
1036 int ret;
ths3b46e622007-09-17 08:09:54 +00001037
bellardfdf9b3e2006-04-27 21:07:38 +00001038 if (cpu_single_env)
1039 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1040#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001041 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001042 pc, address, is_write, *(unsigned long *)old_set);
1043#endif
1044 /* XXX: locking issue */
1045 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1046 return 1;
1047 }
1048
1049 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001050 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001051 if (ret < 0)
1052 return 0; /* not an MMU fault */
1053 if (ret == 0)
1054 return 1; /* the MMU fault was handled without causing real CPU fault */
1055
1056 /* now we have a real cpu fault */
1057 tb = tb_find_pc(pc);
1058 if (tb) {
1059 /* the PC is inside the translated code. It means that we have
1060 a virtual CPU fault */
1061 cpu_restore_state(tb, env, pc, puc);
1062 }
bellardfdf9b3e2006-04-27 21:07:38 +00001063#if 0
ths5fafdf22007-09-16 21:08:06 +00001064 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001065 env->nip, env->error_code, tb);
1066#endif
1067 /* we restore the process signal mask as the sigreturn should
1068 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001069 sigprocmask(SIG_SETMASK, old_set, NULL);
1070 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001071 /* never comes here */
1072 return 1;
1073}
j_mayereddf68a2007-04-05 07:22:49 +00001074
1075#elif defined (TARGET_ALPHA)
1076static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1077 int is_write, sigset_t *old_set,
1078 void *puc)
1079{
1080 TranslationBlock *tb;
1081 int ret;
ths3b46e622007-09-17 08:09:54 +00001082
j_mayereddf68a2007-04-05 07:22:49 +00001083 if (cpu_single_env)
1084 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1085#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001086 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001087 pc, address, is_write, *(unsigned long *)old_set);
1088#endif
1089 /* XXX: locking issue */
1090 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1091 return 1;
1092 }
1093
1094 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001095 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001096 if (ret < 0)
1097 return 0; /* not an MMU fault */
1098 if (ret == 0)
1099 return 1; /* the MMU fault was handled without causing real CPU fault */
1100
1101 /* now we have a real cpu fault */
1102 tb = tb_find_pc(pc);
1103 if (tb) {
1104 /* the PC is inside the translated code. It means that we have
1105 a virtual CPU fault */
1106 cpu_restore_state(tb, env, pc, puc);
1107 }
1108#if 0
ths5fafdf22007-09-16 21:08:06 +00001109 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001110 env->nip, env->error_code, tb);
1111#endif
1112 /* we restore the process signal mask as the sigreturn should
1113 do it (XXX: use sigsetjmp) */
1114 sigprocmask(SIG_SETMASK, old_set, NULL);
1115 cpu_loop_exit();
1116 /* never comes here */
1117 return 1;
1118}
thsf1ccf902007-10-08 13:16:14 +00001119#elif defined (TARGET_CRIS)
1120static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1121 int is_write, sigset_t *old_set,
1122 void *puc)
1123{
1124 TranslationBlock *tb;
1125 int ret;
1126
1127 if (cpu_single_env)
1128 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1129#if defined(DEBUG_SIGNAL)
1130 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1131 pc, address, is_write, *(unsigned long *)old_set);
1132#endif
1133 /* XXX: locking issue */
1134 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1135 return 1;
1136 }
1137
1138 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001139 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001140 if (ret < 0)
1141 return 0; /* not an MMU fault */
1142 if (ret == 0)
1143 return 1; /* the MMU fault was handled without causing real CPU fault */
1144
1145 /* now we have a real cpu fault */
1146 tb = tb_find_pc(pc);
1147 if (tb) {
1148 /* the PC is inside the translated code. It means that we have
1149 a virtual CPU fault */
1150 cpu_restore_state(tb, env, pc, puc);
1151 }
1152#if 0
1153 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1154 env->nip, env->error_code, tb);
1155#endif
1156 /* we restore the process signal mask as the sigreturn should
1157 do it (XXX: use sigsetjmp) */
1158 sigprocmask(SIG_SETMASK, old_set, NULL);
1159 cpu_loop_exit();
1160 /* never comes here */
1161 return 1;
1162}
1163
bellarde4533c72003-06-15 19:51:39 +00001164#else
1165#error unsupported target CPU
1166#endif
bellard9de5e442003-03-23 16:49:39 +00001167
bellard2b413142003-05-14 23:01:10 +00001168#if defined(__i386__)
1169
bellardd8ecc0b2007-02-05 21:41:46 +00001170#if defined(__APPLE__)
1171# include <sys/ucontext.h>
1172
1173# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1174# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1175# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1176#else
1177# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1178# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1179# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1180#endif
1181
ths5fafdf22007-09-16 21:08:06 +00001182int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001183 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001184{
ths5a7b5422007-01-31 12:16:51 +00001185 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001186 struct ucontext *uc = puc;
1187 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001188 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001189
bellardd691f662003-03-24 21:58:34 +00001190#ifndef REG_EIP
1191/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001192#define REG_EIP EIP
1193#define REG_ERR ERR
1194#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001195#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001196 pc = EIP_sig(uc);
1197 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001198 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1199 trapno == 0xe ?
1200 (ERROR_sig(uc) >> 1) & 1 : 0,
1201 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001202}
1203
bellardbc51c5c2004-03-17 23:46:04 +00001204#elif defined(__x86_64__)
1205
ths5a7b5422007-01-31 12:16:51 +00001206int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001207 void *puc)
1208{
ths5a7b5422007-01-31 12:16:51 +00001209 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001210 struct ucontext *uc = puc;
1211 unsigned long pc;
1212
1213 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001214 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1215 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001216 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1217 &uc->uc_sigmask, puc);
1218}
1219
bellard83fb7ad2004-07-05 21:25:26 +00001220#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001221
bellard83fb7ad2004-07-05 21:25:26 +00001222/***********************************************************************
1223 * signal context platform-specific definitions
1224 * From Wine
1225 */
1226#ifdef linux
1227/* All Registers access - only for local access */
1228# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1229/* Gpr Registers access */
1230# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1231# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1232# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1233# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1234# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1235# define LR_sig(context) REG_sig(link, context) /* Link register */
1236# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1237/* Float Registers access */
1238# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1239# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1240/* Exception Registers access */
1241# define DAR_sig(context) REG_sig(dar, context)
1242# define DSISR_sig(context) REG_sig(dsisr, context)
1243# define TRAP_sig(context) REG_sig(trap, context)
1244#endif /* linux */
1245
1246#ifdef __APPLE__
1247# include <sys/ucontext.h>
1248typedef struct ucontext SIGCONTEXT;
1249/* All Registers access - only for local access */
1250# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1251# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1252# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1253# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1254/* Gpr Registers access */
1255# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1256# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1257# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1258# define CTR_sig(context) REG_sig(ctr, context)
1259# define XER_sig(context) REG_sig(xer, context) /* Link register */
1260# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1261# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1262/* Float Registers access */
1263# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1264# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1265/* Exception Registers access */
1266# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1267# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1268# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1269#endif /* __APPLE__ */
1270
ths5fafdf22007-09-16 21:08:06 +00001271int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001272 void *puc)
bellard2b413142003-05-14 23:01:10 +00001273{
ths5a7b5422007-01-31 12:16:51 +00001274 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001275 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001276 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001277 int is_write;
1278
bellard83fb7ad2004-07-05 21:25:26 +00001279 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001280 is_write = 0;
1281#if 0
1282 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001283 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001284 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001285#else
bellard83fb7ad2004-07-05 21:25:26 +00001286 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001287 is_write = 1;
1288#endif
ths5fafdf22007-09-16 21:08:06 +00001289 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001290 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001291}
bellard2b413142003-05-14 23:01:10 +00001292
bellard2f87c602003-06-02 20:38:09 +00001293#elif defined(__alpha__)
1294
ths5fafdf22007-09-16 21:08:06 +00001295int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001296 void *puc)
1297{
ths5a7b5422007-01-31 12:16:51 +00001298 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001299 struct ucontext *uc = puc;
1300 uint32_t *pc = uc->uc_mcontext.sc_pc;
1301 uint32_t insn = *pc;
1302 int is_write = 0;
1303
bellard8c6939c2003-06-09 15:28:00 +00001304 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001305 switch (insn >> 26) {
1306 case 0x0d: // stw
1307 case 0x0e: // stb
1308 case 0x0f: // stq_u
1309 case 0x24: // stf
1310 case 0x25: // stg
1311 case 0x26: // sts
1312 case 0x27: // stt
1313 case 0x2c: // stl
1314 case 0x2d: // stq
1315 case 0x2e: // stl_c
1316 case 0x2f: // stq_c
1317 is_write = 1;
1318 }
1319
ths5fafdf22007-09-16 21:08:06 +00001320 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001321 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001322}
bellard8c6939c2003-06-09 15:28:00 +00001323#elif defined(__sparc__)
1324
ths5fafdf22007-09-16 21:08:06 +00001325int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001326 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001327{
ths5a7b5422007-01-31 12:16:51 +00001328 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001329 uint32_t *regs = (uint32_t *)(info + 1);
1330 void *sigmask = (regs + 20);
1331 unsigned long pc;
1332 int is_write;
1333 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001334
bellard8c6939c2003-06-09 15:28:00 +00001335 /* XXX: is there a standard glibc define ? */
1336 pc = regs[1];
1337 /* XXX: need kernel patch to get write flag faster */
1338 is_write = 0;
1339 insn = *(uint32_t *)pc;
1340 if ((insn >> 30) == 3) {
1341 switch((insn >> 19) & 0x3f) {
1342 case 0x05: // stb
1343 case 0x06: // sth
1344 case 0x04: // st
1345 case 0x07: // std
1346 case 0x24: // stf
1347 case 0x27: // stdf
1348 case 0x25: // stfsr
1349 is_write = 1;
1350 break;
1351 }
1352 }
ths5fafdf22007-09-16 21:08:06 +00001353 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001354 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001355}
1356
1357#elif defined(__arm__)
1358
ths5fafdf22007-09-16 21:08:06 +00001359int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001360 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001361{
ths5a7b5422007-01-31 12:16:51 +00001362 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001363 struct ucontext *uc = puc;
1364 unsigned long pc;
1365 int is_write;
ths3b46e622007-09-17 08:09:54 +00001366
bellard8c6939c2003-06-09 15:28:00 +00001367 pc = uc->uc_mcontext.gregs[R15];
1368 /* 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
bellard2b413142003-05-14 23:01:10 +00001460#else
1461
bellard3fb2ded2003-06-24 13:22:59 +00001462#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001463
1464#endif
bellard67b915a2004-03-31 23:37:16 +00001465
1466#endif /* !defined(CONFIG_SOFTMMU) */