blob: c6db5adf5e6eb523fe38a5878ca813e0fe0afe6c [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
bellard7d132992003-03-06 23:23:54 +00005 *
bellard3ef693a2003-03-23 20:17:16 +00006 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bellard7d132992003-03-06 23:23:54 +000019 */
bellarde4533c72003-06-15 19:51:39 +000020#include "config.h"
bellard7cb69ca2008-05-10 10:55:51 +000021#define CPU_NO_GLOBAL_REGS
bellard93ac68b2003-09-30 20:57:29 +000022#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000023#include "disas.h"
bellard7cb69ca2008-05-10 10:55:51 +000024#include "tcg.h"
aliguori7ba1e612008-11-05 16:04:33 +000025#include "kvm.h"
bellard7d132992003-03-06 23:23:54 +000026
bellardfbf9eeb2004-04-25 21:21:33 +000027#if !defined(CONFIG_SOFTMMU)
28#undef EAX
29#undef ECX
30#undef EDX
31#undef EBX
32#undef ESP
33#undef EBP
34#undef ESI
35#undef EDI
36#undef EIP
37#include <signal.h>
blueswir184778502008-10-26 20:33:16 +000038#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000039#include <sys/ucontext.h>
40#endif
blueswir184778502008-10-26 20:33:16 +000041#endif
bellardfbf9eeb2004-04-25 21:21:33 +000042
blueswir1572a9d42008-05-17 07:38:10 +000043#if defined(__sparc__) && !defined(HOST_SOLARIS)
44// Work around ugly bugs in glibc that mangle global register contents
45#undef env
46#define env cpu_single_env
47#endif
48
bellard36bdbe52003-11-19 22:12:02 +000049int tb_invalidated_flag;
50
bellarddc990652003-03-19 00:00:28 +000051//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000052//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000053
bellarde4533c72003-06-15 19:51:39 +000054void cpu_loop_exit(void)
55{
thsbfed01f2007-06-03 17:44:37 +000056 /* NOTE: the register at this point must be saved by hand because
57 longjmp restore them */
58 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000059 longjmp(env->jmp_env, 1);
60}
thsbfed01f2007-06-03 17:44:37 +000061
bellardfbf9eeb2004-04-25 21:21:33 +000062/* exit the current TB from a signal handler. The host registers are
63 restored in a state compatible with the CPU emulator
64 */
ths5fafdf22007-09-16 21:08:06 +000065void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000066{
67#if !defined(CONFIG_SOFTMMU)
blueswir184778502008-10-26 20:33:16 +000068#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000069 struct ucontext *uc = puc;
blueswir184778502008-10-26 20:33:16 +000070#elif defined(__OpenBSD__)
71 struct sigcontext *uc = puc;
72#endif
bellardfbf9eeb2004-04-25 21:21:33 +000073#endif
74
75 env = env1;
76
77 /* XXX: restore cpu registers saved in host registers */
78
79#if !defined(CONFIG_SOFTMMU)
80 if (puc) {
81 /* XXX: use siglongjmp ? */
blueswir184778502008-10-26 20:33:16 +000082#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000083 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
blueswir184778502008-10-26 20:33:16 +000084#elif defined(__OpenBSD__)
85 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
86#endif
bellardfbf9eeb2004-04-25 21:21:33 +000087 }
88#endif
89 longjmp(env->jmp_env, 1);
90}
91
pbrook2e70f6e2008-06-29 01:03:05 +000092/* Execute the code without caching the generated code. An interpreter
93 could be used if available. */
94static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
95{
96 unsigned long next_tb;
97 TranslationBlock *tb;
98
99 /* Should never happen.
100 We only end up here when an existing TB is too long. */
101 if (max_cycles > CF_COUNT_MASK)
102 max_cycles = CF_COUNT_MASK;
103
104 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
105 max_cycles);
106 env->current_tb = tb;
107 /* execute the generated code */
108 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
109
110 if ((next_tb & 3) == 2) {
111 /* Restore PC. This may happen if async event occurs before
112 the TB starts executing. */
113 CPU_PC_FROM_TB(env, tb);
114 }
115 tb_phys_invalidate(tb, -1);
116 tb_free(tb);
117}
118
bellard8a40a182005-11-20 10:35:40 +0000119static TranslationBlock *tb_find_slow(target_ulong pc,
120 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000121 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000122{
123 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +0000124 unsigned int h;
125 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
ths3b46e622007-09-17 08:09:54 +0000126
bellard8a40a182005-11-20 10:35:40 +0000127 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000128
bellard8a40a182005-11-20 10:35:40 +0000129 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000130
bellard8a40a182005-11-20 10:35:40 +0000131 /* find translated block using physical mappings */
132 phys_pc = get_phys_addr_code(env, pc);
133 phys_page1 = phys_pc & TARGET_PAGE_MASK;
134 phys_page2 = -1;
135 h = tb_phys_hash_func(phys_pc);
136 ptb1 = &tb_phys_hash[h];
137 for(;;) {
138 tb = *ptb1;
139 if (!tb)
140 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000141 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000142 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000143 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000144 tb->flags == flags) {
145 /* check next page if needed */
146 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000147 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000148 TARGET_PAGE_SIZE;
149 phys_page2 = get_phys_addr_code(env, virt_page2);
150 if (tb->page_addr[1] == phys_page2)
151 goto found;
152 } else {
153 goto found;
154 }
155 }
156 ptb1 = &tb->phys_hash_next;
157 }
158 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000159 /* if no translated code available, then translate it now */
160 tb = tb_gen_code(env, pc, cs_base, flags, 0);
ths3b46e622007-09-17 08:09:54 +0000161
bellard8a40a182005-11-20 10:35:40 +0000162 found:
bellard8a40a182005-11-20 10:35:40 +0000163 /* we add the TB in the virtual pc hash table */
164 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
bellard8a40a182005-11-20 10:35:40 +0000165 return tb;
166}
167
168static inline TranslationBlock *tb_find_fast(void)
169{
170 TranslationBlock *tb;
171 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000172 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000173
174 /* we record a subset of the CPU state. It will
175 always be the same before a given translated block
176 is executed. */
177#if defined(TARGET_I386)
178 flags = env->hflags;
179 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
180 cs_base = env->segs[R_CS].base;
181 pc = cs_base + env->eip;
182#elif defined(TARGET_ARM)
183 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000184 | (env->vfp.vec_stride << 4);
185 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
186 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000187 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
188 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000189 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000190 cs_base = 0;
191 pc = env->regs[15];
192#elif defined(TARGET_SPARC)
193#ifdef TARGET_SPARC64
blueswir12cade6a2008-07-17 12:53:05 +0000194 // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
195 flags = ((env->pstate & PS_AM) << 2)
196 | (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
bellarda80dde02006-06-26 19:53:29 +0000197 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000198#else
blueswir16d5f2372007-11-07 17:03:37 +0000199 // FPU enable . Supervisor
200 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000201#endif
202 cs_base = env->npc;
203 pc = env->pc;
204#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000205 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000206 cs_base = 0;
207 pc = env->nip;
208#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000209 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000210 cs_base = 0;
thsb5dc7732008-06-27 10:02:35 +0000211 pc = env->active_tc.PC;
pbrooke6e59062006-10-22 00:18:54 +0000212#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000213 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
214 | (env->sr & SR_S) /* Bit 13 */
215 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000216 cs_base = 0;
217 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000218#elif defined(TARGET_SH4)
aurel32fe255912008-09-15 08:49:15 +0000219 flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
220 | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */
221 | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */
222 | (env->sr & (SR_MD | SR_RB)); /* Bits 29-30 */
ths823029f2007-12-02 06:10:04 +0000223 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000224 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000225#elif defined(TARGET_ALPHA)
226 flags = env->ps;
227 cs_base = 0;
228 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000229#elif defined(TARGET_CRIS)
edgar_igla1aebcb2008-10-07 22:48:41 +0000230 flags = env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG | X_FLAG);
edgar_iglcf1d97f2008-05-13 10:59:14 +0000231 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000232 cs_base = 0;
233 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000234#else
235#error unsupported CPU
236#endif
bellardbce61842008-02-01 22:18:51 +0000237 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000238 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
239 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000240 tb = tb_find_slow(pc, cs_base, flags);
241 }
242 return tb;
243}
244
bellard7d132992003-03-06 23:23:54 +0000245/* main execution loop */
246
bellarde4533c72003-06-15 19:51:39 +0000247int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000248{
pbrook1057eaa2007-02-04 13:37:44 +0000249#define DECLARE_HOST_REGS 1
250#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000251 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000252 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000253 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000254 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000255
thsbfed01f2007-06-03 17:44:37 +0000256 if (cpu_halted(env1) == EXCP_HALTED)
257 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000258
ths5fafdf22007-09-16 21:08:06 +0000259 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000260
bellard7d132992003-03-06 23:23:54 +0000261 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000262#define SAVE_HOST_REGS 1
263#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000264 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000265
bellard0d1a29f2004-10-12 22:01:28 +0000266 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000267#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000268 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000269 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
270 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000271 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000272 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000273#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000274#elif defined(TARGET_M68K)
275 env->cc_op = CC_OP_FLAGS;
276 env->cc_dest = env->sr & 0xf;
277 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000278#elif defined(TARGET_ALPHA)
279#elif defined(TARGET_ARM)
280#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000281#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000282#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000283#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000284 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000285#else
286#error unsupported target CPU
287#endif
bellard3fb2ded2003-06-24 13:22:59 +0000288 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000289
bellard7d132992003-03-06 23:23:54 +0000290 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000291 for(;;) {
292 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000293 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000294 /* if an exception is pending, we execute it here */
295 if (env->exception_index >= 0) {
296 if (env->exception_index >= EXCP_INTERRUPT) {
297 /* exit request from the cpu execution loop */
298 ret = env->exception_index;
299 break;
300 } else if (env->user_mode_only) {
301 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000302 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000303 loop */
bellard83479e72003-06-25 16:12:37 +0000304#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000305 do_interrupt_user(env->exception_index,
306 env->exception_is_int,
307 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000308 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000309 /* successfully delivered */
310 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000311#endif
bellard3fb2ded2003-06-24 13:22:59 +0000312 ret = env->exception_index;
313 break;
314 } else {
bellard83479e72003-06-25 16:12:37 +0000315#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000316 /* simulate a real cpu exception. On i386, it can
317 trigger new exceptions, but we do not handle
318 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000319 do_interrupt(env->exception_index,
320 env->exception_is_int,
321 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000322 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000323 /* successfully delivered */
324 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000325#elif defined(TARGET_PPC)
326 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000327#elif defined(TARGET_MIPS)
328 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000329#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000330 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000331#elif defined(TARGET_ARM)
332 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000333#elif defined(TARGET_SH4)
334 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000335#elif defined(TARGET_ALPHA)
336 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000337#elif defined(TARGET_CRIS)
338 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000339#elif defined(TARGET_M68K)
340 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000341#endif
bellard3fb2ded2003-06-24 13:22:59 +0000342 }
343 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000344 }
bellard9df217a2005-02-10 22:05:51 +0000345#ifdef USE_KQEMU
346 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
347 int ret;
348 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
349 ret = kqemu_cpu_exec(env);
350 /* put eflags in CPU temporary format */
351 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
352 DF = 1 - (2 * ((env->eflags >> 10) & 1));
353 CC_OP = CC_OP_EFLAGS;
354 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
355 if (ret == 1) {
356 /* exception */
357 longjmp(env->jmp_env, 1);
358 } else if (ret == 2) {
359 /* softmmu execution needed */
360 } else {
361 if (env->interrupt_request != 0) {
362 /* hardware interrupt will be executed just after */
363 } else {
364 /* otherwise, we restart */
365 longjmp(env->jmp_env, 1);
366 }
367 }
bellard9de5e442003-03-23 16:49:39 +0000368 }
bellard9df217a2005-02-10 22:05:51 +0000369#endif
370
aliguori7ba1e612008-11-05 16:04:33 +0000371 if (kvm_enabled()) {
372 int ret;
373 ret = kvm_cpu_exec(env);
374 if ((env->interrupt_request & CPU_INTERRUPT_EXIT)) {
375 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
376 env->exception_index = EXCP_INTERRUPT;
377 cpu_loop_exit();
378 } else if (env->halted) {
379 cpu_loop_exit();
380 } else
381 longjmp(env->jmp_env, 1);
382 }
383
blueswir1b5fc09a2008-05-04 06:38:18 +0000384 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000385 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000386 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000387 if (unlikely(interrupt_request)) {
388 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
389 /* Mask out external interrupts for this step. */
390 interrupt_request &= ~(CPU_INTERRUPT_HARD |
391 CPU_INTERRUPT_FIQ |
392 CPU_INTERRUPT_SMI |
393 CPU_INTERRUPT_NMI);
394 }
pbrook6658ffb2007-03-16 23:58:11 +0000395 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
396 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
397 env->exception_index = EXCP_DEBUG;
398 cpu_loop_exit();
399 }
balroga90b7312007-05-01 01:28:01 +0000400#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000401 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000402 if (interrupt_request & CPU_INTERRUPT_HALT) {
403 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
404 env->halted = 1;
405 env->exception_index = EXCP_HLT;
406 cpu_loop_exit();
407 }
408#endif
bellard68a79312003-06-30 13:12:32 +0000409#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000410 if (env->hflags2 & HF2_GIF_MASK) {
411 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
412 !(env->hflags & HF_SMM_MASK)) {
413 svm_check_intercept(SVM_EXIT_SMI);
414 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
415 do_smm_enter();
416 next_tb = 0;
417 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
418 !(env->hflags2 & HF2_NMI_MASK)) {
419 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
420 env->hflags2 |= HF2_NMI_MASK;
421 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
422 next_tb = 0;
423 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
424 (((env->hflags2 & HF2_VINTR_MASK) &&
425 (env->hflags2 & HF2_HIF_MASK)) ||
426 (!(env->hflags2 & HF2_VINTR_MASK) &&
427 (env->eflags & IF_MASK &&
428 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
429 int intno;
430 svm_check_intercept(SVM_EXIT_INTR);
431 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
432 intno = cpu_get_pic_interrupt(env);
433 if (loglevel & CPU_LOG_TB_IN_ASM) {
434 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
435 }
436 do_interrupt(intno, 0, 0, 0, 1);
437 /* ensure that no TB jump will be modified as
438 the program flow was changed */
439 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000440#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000441 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
442 (env->eflags & IF_MASK) &&
443 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
444 int intno;
445 /* FIXME: this should respect TPR */
446 svm_check_intercept(SVM_EXIT_VINTR);
447 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
448 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
449 if (loglevel & CPU_LOG_TB_IN_ASM)
450 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
451 do_interrupt(intno, 0, 0, 0, 1);
452 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000453#endif
bellarddb620f42008-06-04 17:02:19 +0000454 }
bellard68a79312003-06-30 13:12:32 +0000455 }
bellardce097762004-01-04 23:53:18 +0000456#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000457#if 0
458 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
459 cpu_ppc_reset(env);
460 }
461#endif
j_mayer47103572007-03-30 09:38:04 +0000462 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000463 ppc_hw_interrupt(env);
464 if (env->pending_interrupts == 0)
465 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000466 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000467 }
bellard6af0bf92005-07-02 14:58:51 +0000468#elif defined(TARGET_MIPS)
469 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000470 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000471 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000472 !(env->CP0_Status & (1 << CP0St_EXL)) &&
473 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000474 !(env->hflags & MIPS_HFLAG_DM)) {
475 /* Raise it */
476 env->exception_index = EXCP_EXT_INTERRUPT;
477 env->error_code = 0;
478 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000479 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000480 }
bellarde95c8d52004-09-30 22:22:08 +0000481#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000482 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
483 (env->psret != 0)) {
484 int pil = env->interrupt_index & 15;
485 int type = env->interrupt_index & 0xf0;
486
487 if (((type == TT_EXTINT) &&
488 (pil == 15 || pil > env->psrpil)) ||
489 type != TT_EXTINT) {
490 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000491 env->exception_index = env->interrupt_index;
492 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000493 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000494#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
495 cpu_check_irqs(env);
496#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000497 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000498 }
bellarde95c8d52004-09-30 22:22:08 +0000499 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
500 //do_interrupt(0, 0, 0, 0, 0);
501 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000502 }
bellardb5ff1b32005-11-26 10:38:39 +0000503#elif defined(TARGET_ARM)
504 if (interrupt_request & CPU_INTERRUPT_FIQ
505 && !(env->uncached_cpsr & CPSR_F)) {
506 env->exception_index = EXCP_FIQ;
507 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000508 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000509 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000510 /* ARMv7-M interrupt return works by loading a magic value
511 into the PC. On real hardware the load causes the
512 return to occur. The qemu implementation performs the
513 jump normally, then does the exception return when the
514 CPU tries to execute code at the magic address.
515 This will cause the magic PC value to be pushed to
516 the stack if an interrupt occured at the wrong time.
517 We avoid this by disabling interrupts when
518 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000519 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000520 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
521 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000522 env->exception_index = EXCP_IRQ;
523 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000524 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000525 }
bellardfdf9b3e2006-04-27 21:07:38 +0000526#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000527 if (interrupt_request & CPU_INTERRUPT_HARD) {
528 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000529 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000530 }
j_mayereddf68a2007-04-05 07:22:49 +0000531#elif defined(TARGET_ALPHA)
532 if (interrupt_request & CPU_INTERRUPT_HARD) {
533 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000534 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000535 }
thsf1ccf902007-10-08 13:16:14 +0000536#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000537 if (interrupt_request & CPU_INTERRUPT_HARD
538 && (env->pregs[PR_CCS] & I_FLAG)) {
539 env->exception_index = EXCP_IRQ;
540 do_interrupt(env);
541 next_tb = 0;
542 }
543 if (interrupt_request & CPU_INTERRUPT_NMI
544 && (env->pregs[PR_CCS] & M_FLAG)) {
545 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000546 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000547 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000548 }
pbrook06338792007-05-23 19:58:11 +0000549#elif defined(TARGET_M68K)
550 if (interrupt_request & CPU_INTERRUPT_HARD
551 && ((env->sr & SR_I) >> SR_I_SHIFT)
552 < env->pending_level) {
553 /* Real hardware gets the interrupt vector via an
554 IACK cycle at this point. Current emulated
555 hardware doesn't rely on this, so we
556 provide/save the vector when the interrupt is
557 first signalled. */
558 env->exception_index = env->pending_vector;
559 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000560 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000561 }
bellard68a79312003-06-30 13:12:32 +0000562#endif
bellard9d050952006-05-22 22:03:52 +0000563 /* Don't use the cached interupt_request value,
564 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000565 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000566 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
567 /* ensure that no TB jump will be modified as
568 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000569 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000570 }
bellard68a79312003-06-30 13:12:32 +0000571 if (interrupt_request & CPU_INTERRUPT_EXIT) {
572 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
573 env->exception_index = EXCP_INTERRUPT;
574 cpu_loop_exit();
575 }
bellard3fb2ded2003-06-24 13:22:59 +0000576 }
577#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000578 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000579 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000580 regs_to_env();
581#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000582 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000583 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000584 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000585#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000586 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000587#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000588 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000589#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000590 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000591#elif defined(TARGET_M68K)
592 cpu_m68k_flush_flags(env, env->cc_op);
593 env->cc_op = CC_OP_FLAGS;
594 env->sr = (env->sr & 0xffe0)
595 | env->cc_dest | (env->cc_x << 4);
596 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000597#elif defined(TARGET_MIPS)
598 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000599#elif defined(TARGET_SH4)
600 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000601#elif defined(TARGET_ALPHA)
602 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000603#elif defined(TARGET_CRIS)
604 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000605#else
ths5fafdf22007-09-16 21:08:06 +0000606#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000607#endif
bellard3fb2ded2003-06-24 13:22:59 +0000608 }
bellard7d132992003-03-06 23:23:54 +0000609#endif
pbrookd5975362008-06-07 20:50:51 +0000610 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000611 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000612 /* Note: we do it here to avoid a gcc bug on Mac OS X when
613 doing it in tb_find_slow */
614 if (tb_invalidated_flag) {
615 /* as some TB could have been invalidated because
616 of memory exceptions while generating the code, we
617 must recompute the hash index here */
618 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000619 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000620 }
bellard9d27abd2003-05-10 13:13:54 +0000621#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000622 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000623 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
624 (long)tb->tc_ptr, tb->pc,
625 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000626 }
bellard9d27abd2003-05-10 13:13:54 +0000627#endif
bellard8a40a182005-11-20 10:35:40 +0000628 /* see if we can patch the calling TB. When the TB
629 spans two pages, we cannot safely do a direct
630 jump. */
bellardc27004e2005-01-03 23:35:10 +0000631 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000632 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000633#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000634 (env->kqemu_enabled != 2) &&
635#endif
bellardec6338b2007-11-08 14:25:03 +0000636 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000637 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000638 }
bellardc27004e2005-01-03 23:35:10 +0000639 }
pbrookd5975362008-06-07 20:50:51 +0000640 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000641 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000642
643 /* cpu_interrupt might be called while translating the
644 TB, but before it is linked into a potentially
645 infinite loop and becomes env->current_tb. Avoid
646 starting execution if there is a pending interrupt. */
647 if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
648 env->current_tb = NULL;
649
pbrook2e70f6e2008-06-29 01:03:05 +0000650 while (env->current_tb) {
651 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000652 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000653#if defined(__sparc__) && !defined(HOST_SOLARIS)
654#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000655 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000656#define env cpu_single_env
657#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000658 next_tb = tcg_qemu_tb_exec(tc_ptr);
659 env->current_tb = NULL;
660 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000661 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000662 int insns_left;
663 tb = (TranslationBlock *)(long)(next_tb & ~3);
664 /* Restore PC. */
665 CPU_PC_FROM_TB(env, tb);
666 insns_left = env->icount_decr.u32;
667 if (env->icount_extra && insns_left >= 0) {
668 /* Refill decrementer and continue execution. */
669 env->icount_extra += insns_left;
670 if (env->icount_extra > 0xffff) {
671 insns_left = 0xffff;
672 } else {
673 insns_left = env->icount_extra;
674 }
675 env->icount_extra -= insns_left;
676 env->icount_decr.u16.low = insns_left;
677 } else {
678 if (insns_left > 0) {
679 /* Execute remaining instructions. */
680 cpu_exec_nocache(insns_left, tb);
681 }
682 env->exception_index = EXCP_INTERRUPT;
683 next_tb = 0;
684 cpu_loop_exit();
685 }
686 }
687 }
bellard4cbf74b2003-08-10 21:48:43 +0000688 /* reset soft MMU for next block (it can currently
689 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000690#if defined(USE_KQEMU)
691#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
692 if (kqemu_is_ok(env) &&
693 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
694 cpu_loop_exit();
695 }
696#endif
ths50a518e2007-06-03 18:52:15 +0000697 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000698 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000699 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000700 }
bellard3fb2ded2003-06-24 13:22:59 +0000701 } /* for(;;) */
702
bellard7d132992003-03-06 23:23:54 +0000703
bellarde4533c72003-06-15 19:51:39 +0000704#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000705 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000706 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000707#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000708 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000709#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000710#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000711#elif defined(TARGET_M68K)
712 cpu_m68k_flush_flags(env, env->cc_op);
713 env->cc_op = CC_OP_FLAGS;
714 env->sr = (env->sr & 0xffe0)
715 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000716#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000717#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000718#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000719#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000720 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000721#else
722#error unsupported target CPU
723#endif
pbrook1057eaa2007-02-04 13:37:44 +0000724
725 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000726#include "hostregs_helper.h"
727
bellard6a00d602005-11-21 23:25:50 +0000728 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000729 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000730 return ret;
731}
bellard6dbad632003-03-16 18:05:05 +0000732
bellardfbf9eeb2004-04-25 21:21:33 +0000733/* must only be called from the generated code as an exception can be
734 generated */
735void tb_invalidate_page_range(target_ulong start, target_ulong end)
736{
bellarddc5d0b32004-06-22 18:43:30 +0000737 /* XXX: cannot enable it yet because it yields to MMU exception
738 where NIP != read address on PowerPC */
739#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000740 target_ulong phys_addr;
741 phys_addr = get_phys_addr_code(env, start);
742 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000743#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000744}
745
bellard1a18c712003-10-30 01:07:51 +0000746#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000747
bellard6dbad632003-03-16 18:05:05 +0000748void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
749{
750 CPUX86State *saved_env;
751
752 saved_env = env;
753 env = s;
bellarda412ac52003-07-26 18:01:40 +0000754 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000755 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000756 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000757 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000758 } else {
bellard5d975592008-05-12 22:05:33 +0000759 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000760 }
bellard6dbad632003-03-16 18:05:05 +0000761 env = saved_env;
762}
bellard9de5e442003-03-23 16:49:39 +0000763
bellard6f12a2a2007-11-11 22:16:56 +0000764void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000765{
766 CPUX86State *saved_env;
767
768 saved_env = env;
769 env = s;
ths3b46e622007-09-17 08:09:54 +0000770
bellard6f12a2a2007-11-11 22:16:56 +0000771 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000772
773 env = saved_env;
774}
775
bellard6f12a2a2007-11-11 22:16:56 +0000776void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000777{
778 CPUX86State *saved_env;
779
780 saved_env = env;
781 env = s;
ths3b46e622007-09-17 08:09:54 +0000782
bellard6f12a2a2007-11-11 22:16:56 +0000783 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000784
785 env = saved_env;
786}
787
bellarde4533c72003-06-15 19:51:39 +0000788#endif /* TARGET_I386 */
789
bellard67b915a2004-03-31 23:37:16 +0000790#if !defined(CONFIG_SOFTMMU)
791
bellard3fb2ded2003-06-24 13:22:59 +0000792#if defined(TARGET_I386)
793
bellardb56dad12003-05-08 15:38:04 +0000794/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000795 the effective address of the memory exception. 'is_write' is 1 if a
796 write caused the exception and otherwise 0'. 'old_set' is the
797 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000798static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000799 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000800 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000801{
bellarda513fe12003-05-27 23:29:48 +0000802 TranslationBlock *tb;
803 int ret;
bellard68a79312003-06-30 13:12:32 +0000804
bellard83479e72003-06-25 16:12:37 +0000805 if (cpu_single_env)
806 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000807#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000808 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000809 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000810#endif
bellard25eb4482003-05-14 21:50:54 +0000811 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000812 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000813 return 1;
814 }
bellardfbf9eeb2004-04-25 21:21:33 +0000815
bellard3fb2ded2003-06-24 13:22:59 +0000816 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000817 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000818 if (ret < 0)
819 return 0; /* not an MMU fault */
820 if (ret == 0)
821 return 1; /* the MMU fault was handled without causing real CPU fault */
822 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000823 tb = tb_find_pc(pc);
824 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000825 /* the PC is inside the translated code. It means that we have
826 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000827 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000828 }
bellard4cbf74b2003-08-10 21:48:43 +0000829 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000830#if 0
ths5fafdf22007-09-16 21:08:06 +0000831 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000832 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000833#endif
bellard4cbf74b2003-08-10 21:48:43 +0000834 /* we restore the process signal mask as the sigreturn should
835 do it (XXX: use sigsetjmp) */
836 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000837 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000838 } else {
839 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000840 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000841 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000842 }
bellard3fb2ded2003-06-24 13:22:59 +0000843 /* never comes here */
844 return 1;
845}
846
bellarde4533c72003-06-15 19:51:39 +0000847#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000848static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000849 int is_write, sigset_t *old_set,
850 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000851{
bellard68016c62005-02-07 23:12:27 +0000852 TranslationBlock *tb;
853 int ret;
854
855 if (cpu_single_env)
856 env = cpu_single_env; /* XXX: find a correct solution for multithread */
857#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000858 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000859 pc, address, is_write, *(unsigned long *)old_set);
860#endif
bellard9f0777e2005-02-02 20:42:01 +0000861 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000862 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000863 return 1;
864 }
bellard68016c62005-02-07 23:12:27 +0000865 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000866 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000867 if (ret < 0)
868 return 0; /* not an MMU fault */
869 if (ret == 0)
870 return 1; /* the MMU fault was handled without causing real CPU fault */
871 /* now we have a real cpu fault */
872 tb = tb_find_pc(pc);
873 if (tb) {
874 /* the PC is inside the translated code. It means that we have
875 a virtual CPU fault */
876 cpu_restore_state(tb, env, pc, puc);
877 }
878 /* we restore the process signal mask as the sigreturn should
879 do it (XXX: use sigsetjmp) */
880 sigprocmask(SIG_SETMASK, old_set, NULL);
881 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000882 /* never comes here */
883 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000884}
bellard93ac68b2003-09-30 20:57:29 +0000885#elif defined(TARGET_SPARC)
886static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000887 int is_write, sigset_t *old_set,
888 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000889{
bellard68016c62005-02-07 23:12:27 +0000890 TranslationBlock *tb;
891 int ret;
892
893 if (cpu_single_env)
894 env = cpu_single_env; /* XXX: find a correct solution for multithread */
895#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000896 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000897 pc, address, is_write, *(unsigned long *)old_set);
898#endif
bellardb453b702004-01-04 15:45:21 +0000899 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000900 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000901 return 1;
902 }
bellard68016c62005-02-07 23:12:27 +0000903 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000904 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000905 if (ret < 0)
906 return 0; /* not an MMU fault */
907 if (ret == 0)
908 return 1; /* the MMU fault was handled without causing real CPU fault */
909 /* now we have a real cpu fault */
910 tb = tb_find_pc(pc);
911 if (tb) {
912 /* the PC is inside the translated code. It means that we have
913 a virtual CPU fault */
914 cpu_restore_state(tb, env, pc, puc);
915 }
916 /* we restore the process signal mask as the sigreturn should
917 do it (XXX: use sigsetjmp) */
918 sigprocmask(SIG_SETMASK, old_set, NULL);
919 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000920 /* never comes here */
921 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000922}
bellard67867302003-11-23 17:05:30 +0000923#elif defined (TARGET_PPC)
924static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000925 int is_write, sigset_t *old_set,
926 void *puc)
bellard67867302003-11-23 17:05:30 +0000927{
928 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000929 int ret;
ths3b46e622007-09-17 08:09:54 +0000930
bellard67867302003-11-23 17:05:30 +0000931 if (cpu_single_env)
932 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000933#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000934 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000935 pc, address, is_write, *(unsigned long *)old_set);
936#endif
937 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000938 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000939 return 1;
940 }
941
bellardce097762004-01-04 23:53:18 +0000942 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000943 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000944 if (ret < 0)
945 return 0; /* not an MMU fault */
946 if (ret == 0)
947 return 1; /* the MMU fault was handled without causing real CPU fault */
948
bellard67867302003-11-23 17:05:30 +0000949 /* now we have a real cpu fault */
950 tb = tb_find_pc(pc);
951 if (tb) {
952 /* the PC is inside the translated code. It means that we have
953 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000954 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000955 }
bellardce097762004-01-04 23:53:18 +0000956 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000957#if 0
ths5fafdf22007-09-16 21:08:06 +0000958 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000959 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000960#endif
961 /* we restore the process signal mask as the sigreturn should
962 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000963 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000964 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000965 } else {
966 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000967 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000968 }
bellard67867302003-11-23 17:05:30 +0000969 /* never comes here */
970 return 1;
971}
bellard6af0bf92005-07-02 14:58:51 +0000972
pbrooke6e59062006-10-22 00:18:54 +0000973#elif defined(TARGET_M68K)
974static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
975 int is_write, sigset_t *old_set,
976 void *puc)
977{
978 TranslationBlock *tb;
979 int ret;
980
981 if (cpu_single_env)
982 env = cpu_single_env; /* XXX: find a correct solution for multithread */
983#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000984 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000985 pc, address, is_write, *(unsigned long *)old_set);
986#endif
987 /* XXX: locking issue */
988 if (is_write && page_unprotect(address, pc, puc)) {
989 return 1;
990 }
991 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000992 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000993 if (ret < 0)
994 return 0; /* not an MMU fault */
995 if (ret == 0)
996 return 1; /* the MMU fault was handled without causing real CPU fault */
997 /* now we have a real cpu fault */
998 tb = tb_find_pc(pc);
999 if (tb) {
1000 /* the PC is inside the translated code. It means that we have
1001 a virtual CPU fault */
1002 cpu_restore_state(tb, env, pc, puc);
1003 }
1004 /* we restore the process signal mask as the sigreturn should
1005 do it (XXX: use sigsetjmp) */
1006 sigprocmask(SIG_SETMASK, old_set, NULL);
1007 cpu_loop_exit();
1008 /* never comes here */
1009 return 1;
1010}
1011
bellard6af0bf92005-07-02 14:58:51 +00001012#elif defined (TARGET_MIPS)
1013static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1014 int is_write, sigset_t *old_set,
1015 void *puc)
1016{
1017 TranslationBlock *tb;
1018 int ret;
ths3b46e622007-09-17 08:09:54 +00001019
bellard6af0bf92005-07-02 14:58:51 +00001020 if (cpu_single_env)
1021 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1022#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001023 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001024 pc, address, is_write, *(unsigned long *)old_set);
1025#endif
1026 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001027 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001028 return 1;
1029 }
1030
1031 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001032 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001033 if (ret < 0)
1034 return 0; /* not an MMU fault */
1035 if (ret == 0)
1036 return 1; /* the MMU fault was handled without causing real CPU fault */
1037
1038 /* now we have a real cpu fault */
1039 tb = tb_find_pc(pc);
1040 if (tb) {
1041 /* the PC is inside the translated code. It means that we have
1042 a virtual CPU fault */
1043 cpu_restore_state(tb, env, pc, puc);
1044 }
1045 if (ret == 1) {
1046#if 0
ths5fafdf22007-09-16 21:08:06 +00001047 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001048 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001049#endif
1050 /* we restore the process signal mask as the sigreturn should
1051 do it (XXX: use sigsetjmp) */
1052 sigprocmask(SIG_SETMASK, old_set, NULL);
1053 do_raise_exception_err(env->exception_index, env->error_code);
1054 } else {
1055 /* activate soft MMU for this block */
1056 cpu_resume_from_signal(env, puc);
1057 }
1058 /* never comes here */
1059 return 1;
1060}
1061
bellardfdf9b3e2006-04-27 21:07:38 +00001062#elif defined (TARGET_SH4)
1063static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1064 int is_write, sigset_t *old_set,
1065 void *puc)
1066{
1067 TranslationBlock *tb;
1068 int ret;
ths3b46e622007-09-17 08:09:54 +00001069
bellardfdf9b3e2006-04-27 21:07:38 +00001070 if (cpu_single_env)
1071 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1072#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001073 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001074 pc, address, is_write, *(unsigned long *)old_set);
1075#endif
1076 /* XXX: locking issue */
1077 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1078 return 1;
1079 }
1080
1081 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001082 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001083 if (ret < 0)
1084 return 0; /* not an MMU fault */
1085 if (ret == 0)
1086 return 1; /* the MMU fault was handled without causing real CPU fault */
1087
1088 /* now we have a real cpu fault */
1089 tb = tb_find_pc(pc);
1090 if (tb) {
1091 /* the PC is inside the translated code. It means that we have
1092 a virtual CPU fault */
1093 cpu_restore_state(tb, env, pc, puc);
1094 }
bellardfdf9b3e2006-04-27 21:07:38 +00001095#if 0
ths5fafdf22007-09-16 21:08:06 +00001096 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001097 env->nip, env->error_code, tb);
1098#endif
1099 /* we restore the process signal mask as the sigreturn should
1100 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001101 sigprocmask(SIG_SETMASK, old_set, NULL);
1102 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001103 /* never comes here */
1104 return 1;
1105}
j_mayereddf68a2007-04-05 07:22:49 +00001106
1107#elif defined (TARGET_ALPHA)
1108static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1109 int is_write, sigset_t *old_set,
1110 void *puc)
1111{
1112 TranslationBlock *tb;
1113 int ret;
ths3b46e622007-09-17 08:09:54 +00001114
j_mayereddf68a2007-04-05 07:22:49 +00001115 if (cpu_single_env)
1116 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1117#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001118 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001119 pc, address, is_write, *(unsigned long *)old_set);
1120#endif
1121 /* XXX: locking issue */
1122 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1123 return 1;
1124 }
1125
1126 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001127 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001128 if (ret < 0)
1129 return 0; /* not an MMU fault */
1130 if (ret == 0)
1131 return 1; /* the MMU fault was handled without causing real CPU fault */
1132
1133 /* now we have a real cpu fault */
1134 tb = tb_find_pc(pc);
1135 if (tb) {
1136 /* the PC is inside the translated code. It means that we have
1137 a virtual CPU fault */
1138 cpu_restore_state(tb, env, pc, puc);
1139 }
1140#if 0
ths5fafdf22007-09-16 21:08:06 +00001141 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001142 env->nip, env->error_code, tb);
1143#endif
1144 /* we restore the process signal mask as the sigreturn should
1145 do it (XXX: use sigsetjmp) */
1146 sigprocmask(SIG_SETMASK, old_set, NULL);
1147 cpu_loop_exit();
1148 /* never comes here */
1149 return 1;
1150}
thsf1ccf902007-10-08 13:16:14 +00001151#elif defined (TARGET_CRIS)
1152static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1153 int is_write, sigset_t *old_set,
1154 void *puc)
1155{
1156 TranslationBlock *tb;
1157 int ret;
1158
1159 if (cpu_single_env)
1160 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1161#if defined(DEBUG_SIGNAL)
1162 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1163 pc, address, is_write, *(unsigned long *)old_set);
1164#endif
1165 /* XXX: locking issue */
1166 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1167 return 1;
1168 }
1169
1170 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001171 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001172 if (ret < 0)
1173 return 0; /* not an MMU fault */
1174 if (ret == 0)
1175 return 1; /* the MMU fault was handled without causing real CPU fault */
1176
1177 /* now we have a real cpu fault */
1178 tb = tb_find_pc(pc);
1179 if (tb) {
1180 /* the PC is inside the translated code. It means that we have
1181 a virtual CPU fault */
1182 cpu_restore_state(tb, env, pc, puc);
1183 }
thsf1ccf902007-10-08 13:16:14 +00001184 /* we restore the process signal mask as the sigreturn should
1185 do it (XXX: use sigsetjmp) */
1186 sigprocmask(SIG_SETMASK, old_set, NULL);
1187 cpu_loop_exit();
1188 /* never comes here */
1189 return 1;
1190}
1191
bellarde4533c72003-06-15 19:51:39 +00001192#else
1193#error unsupported target CPU
1194#endif
bellard9de5e442003-03-23 16:49:39 +00001195
bellard2b413142003-05-14 23:01:10 +00001196#if defined(__i386__)
1197
bellardd8ecc0b2007-02-05 21:41:46 +00001198#if defined(__APPLE__)
1199# include <sys/ucontext.h>
1200
1201# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1202# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1203# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1204#else
1205# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1206# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1207# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1208#endif
1209
ths5fafdf22007-09-16 21:08:06 +00001210int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001211 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001212{
ths5a7b5422007-01-31 12:16:51 +00001213 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001214 struct ucontext *uc = puc;
1215 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001216 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001217
bellardd691f662003-03-24 21:58:34 +00001218#ifndef REG_EIP
1219/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001220#define REG_EIP EIP
1221#define REG_ERR ERR
1222#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001223#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001224 pc = EIP_sig(uc);
1225 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001226 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1227 trapno == 0xe ?
1228 (ERROR_sig(uc) >> 1) & 1 : 0,
1229 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001230}
1231
bellardbc51c5c2004-03-17 23:46:04 +00001232#elif defined(__x86_64__)
1233
ths5a7b5422007-01-31 12:16:51 +00001234int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001235 void *puc)
1236{
ths5a7b5422007-01-31 12:16:51 +00001237 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001238 struct ucontext *uc = puc;
1239 unsigned long pc;
1240
1241 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001242 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1243 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001244 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1245 &uc->uc_sigmask, puc);
1246}
1247
bellard83fb7ad2004-07-05 21:25:26 +00001248#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001249
bellard83fb7ad2004-07-05 21:25:26 +00001250/***********************************************************************
1251 * signal context platform-specific definitions
1252 * From Wine
1253 */
1254#ifdef linux
1255/* All Registers access - only for local access */
1256# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1257/* Gpr Registers access */
1258# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1259# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1260# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1261# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1262# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1263# define LR_sig(context) REG_sig(link, context) /* Link register */
1264# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1265/* Float Registers access */
1266# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1267# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1268/* Exception Registers access */
1269# define DAR_sig(context) REG_sig(dar, context)
1270# define DSISR_sig(context) REG_sig(dsisr, context)
1271# define TRAP_sig(context) REG_sig(trap, context)
1272#endif /* linux */
1273
1274#ifdef __APPLE__
1275# include <sys/ucontext.h>
1276typedef struct ucontext SIGCONTEXT;
1277/* All Registers access - only for local access */
1278# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1279# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1280# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1281# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1282/* Gpr Registers access */
1283# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1284# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1285# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1286# define CTR_sig(context) REG_sig(ctr, context)
1287# define XER_sig(context) REG_sig(xer, context) /* Link register */
1288# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1289# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1290/* Float Registers access */
1291# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1292# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1293/* Exception Registers access */
1294# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1295# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1296# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1297#endif /* __APPLE__ */
1298
ths5fafdf22007-09-16 21:08:06 +00001299int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001300 void *puc)
bellard2b413142003-05-14 23:01:10 +00001301{
ths5a7b5422007-01-31 12:16:51 +00001302 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001303 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001304 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001305 int is_write;
1306
bellard83fb7ad2004-07-05 21:25:26 +00001307 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001308 is_write = 0;
1309#if 0
1310 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001311 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001312 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001313#else
bellard83fb7ad2004-07-05 21:25:26 +00001314 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001315 is_write = 1;
1316#endif
ths5fafdf22007-09-16 21:08:06 +00001317 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001318 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001319}
bellard2b413142003-05-14 23:01:10 +00001320
bellard2f87c602003-06-02 20:38:09 +00001321#elif defined(__alpha__)
1322
ths5fafdf22007-09-16 21:08:06 +00001323int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001324 void *puc)
1325{
ths5a7b5422007-01-31 12:16:51 +00001326 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001327 struct ucontext *uc = puc;
1328 uint32_t *pc = uc->uc_mcontext.sc_pc;
1329 uint32_t insn = *pc;
1330 int is_write = 0;
1331
bellard8c6939c2003-06-09 15:28:00 +00001332 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001333 switch (insn >> 26) {
1334 case 0x0d: // stw
1335 case 0x0e: // stb
1336 case 0x0f: // stq_u
1337 case 0x24: // stf
1338 case 0x25: // stg
1339 case 0x26: // sts
1340 case 0x27: // stt
1341 case 0x2c: // stl
1342 case 0x2d: // stq
1343 case 0x2e: // stl_c
1344 case 0x2f: // stq_c
1345 is_write = 1;
1346 }
1347
ths5fafdf22007-09-16 21:08:06 +00001348 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001349 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001350}
bellard8c6939c2003-06-09 15:28:00 +00001351#elif defined(__sparc__)
1352
ths5fafdf22007-09-16 21:08:06 +00001353int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001354 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001355{
ths5a7b5422007-01-31 12:16:51 +00001356 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001357 int is_write;
1358 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001359#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001360 uint32_t *regs = (uint32_t *)(info + 1);
1361 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001362 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001363 unsigned long pc = regs[1];
1364#else
blueswir184778502008-10-26 20:33:16 +00001365#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001366 struct sigcontext *sc = puc;
1367 unsigned long pc = sc->sigc_regs.tpc;
1368 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001369#elif defined(__OpenBSD__)
1370 struct sigcontext *uc = puc;
1371 unsigned long pc = uc->sc_pc;
1372 void *sigmask = (void *)(long)uc->sc_mask;
1373#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001374#endif
1375
bellard8c6939c2003-06-09 15:28:00 +00001376 /* XXX: need kernel patch to get write flag faster */
1377 is_write = 0;
1378 insn = *(uint32_t *)pc;
1379 if ((insn >> 30) == 3) {
1380 switch((insn >> 19) & 0x3f) {
1381 case 0x05: // stb
1382 case 0x06: // sth
1383 case 0x04: // st
1384 case 0x07: // std
1385 case 0x24: // stf
1386 case 0x27: // stdf
1387 case 0x25: // stfsr
1388 is_write = 1;
1389 break;
1390 }
1391 }
ths5fafdf22007-09-16 21:08:06 +00001392 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001393 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001394}
1395
1396#elif defined(__arm__)
1397
ths5fafdf22007-09-16 21:08:06 +00001398int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001399 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001400{
ths5a7b5422007-01-31 12:16:51 +00001401 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001402 struct ucontext *uc = puc;
1403 unsigned long pc;
1404 int is_write;
ths3b46e622007-09-17 08:09:54 +00001405
blueswir148bbf112008-07-08 18:35:02 +00001406#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001407 pc = uc->uc_mcontext.gregs[R15];
1408#else
balrog4eee57f2008-05-06 14:47:19 +00001409 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001410#endif
bellard8c6939c2003-06-09 15:28:00 +00001411 /* XXX: compute is_write */
1412 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001413 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001414 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001415 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001416}
1417
bellard38e584a2003-08-10 22:14:22 +00001418#elif defined(__mc68000)
1419
ths5fafdf22007-09-16 21:08:06 +00001420int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001421 void *puc)
1422{
ths5a7b5422007-01-31 12:16:51 +00001423 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001424 struct ucontext *uc = puc;
1425 unsigned long pc;
1426 int is_write;
ths3b46e622007-09-17 08:09:54 +00001427
bellard38e584a2003-08-10 22:14:22 +00001428 pc = uc->uc_mcontext.gregs[16];
1429 /* XXX: compute is_write */
1430 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001431 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001432 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001433 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001434}
1435
bellardb8076a72005-04-07 22:20:31 +00001436#elif defined(__ia64)
1437
1438#ifndef __ISR_VALID
1439 /* This ought to be in <bits/siginfo.h>... */
1440# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001441#endif
1442
ths5a7b5422007-01-31 12:16:51 +00001443int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001444{
ths5a7b5422007-01-31 12:16:51 +00001445 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001446 struct ucontext *uc = puc;
1447 unsigned long ip;
1448 int is_write = 0;
1449
1450 ip = uc->uc_mcontext.sc_ip;
1451 switch (host_signum) {
1452 case SIGILL:
1453 case SIGFPE:
1454 case SIGSEGV:
1455 case SIGBUS:
1456 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001457 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001458 /* ISR.W (write-access) is bit 33: */
1459 is_write = (info->si_isr >> 33) & 1;
1460 break;
1461
1462 default:
1463 break;
1464 }
1465 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1466 is_write,
1467 &uc->uc_sigmask, puc);
1468}
1469
bellard90cb9492005-07-24 15:11:38 +00001470#elif defined(__s390__)
1471
ths5fafdf22007-09-16 21:08:06 +00001472int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001473 void *puc)
1474{
ths5a7b5422007-01-31 12:16:51 +00001475 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001476 struct ucontext *uc = puc;
1477 unsigned long pc;
1478 int is_write;
ths3b46e622007-09-17 08:09:54 +00001479
bellard90cb9492005-07-24 15:11:38 +00001480 pc = uc->uc_mcontext.psw.addr;
1481 /* XXX: compute is_write */
1482 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001483 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001484 is_write, &uc->uc_sigmask, puc);
1485}
1486
1487#elif defined(__mips__)
1488
ths5fafdf22007-09-16 21:08:06 +00001489int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001490 void *puc)
1491{
ths9617efe2007-05-08 21:05:55 +00001492 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001493 struct ucontext *uc = puc;
1494 greg_t pc = uc->uc_mcontext.pc;
1495 int is_write;
ths3b46e622007-09-17 08:09:54 +00001496
thsc4b89d12007-05-05 19:23:11 +00001497 /* XXX: compute is_write */
1498 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001499 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001500 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001501}
1502
aurel32f54b3f92008-04-12 20:14:54 +00001503#elif defined(__hppa__)
1504
1505int cpu_signal_handler(int host_signum, void *pinfo,
1506 void *puc)
1507{
1508 struct siginfo *info = pinfo;
1509 struct ucontext *uc = puc;
1510 unsigned long pc;
1511 int is_write;
1512
1513 pc = uc->uc_mcontext.sc_iaoq[0];
1514 /* FIXME: compute is_write */
1515 is_write = 0;
1516 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1517 is_write,
1518 &uc->uc_sigmask, puc);
1519}
1520
bellard2b413142003-05-14 23:01:10 +00001521#else
1522
bellard3fb2ded2003-06-24 13:22:59 +00001523#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001524
1525#endif
bellard67b915a2004-03-31 23:37:16 +00001526
1527#endif /* !defined(CONFIG_SOFTMMU) */