blob: b3662400ffe712ee8521f5c885a7c4756a6145d4 [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
pbrooke6e59062006-10-22 00:18:54 +000062#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +000063#define reg_T2
64#endif
bellarde4533c72003-06-15 19:51:39 +000065
bellardfbf9eeb2004-04-25 21:21:33 +000066/* exit the current TB from a signal handler. The host registers are
67 restored in a state compatible with the CPU emulator
68 */
ths5fafdf22007-09-16 21:08:06 +000069void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000070{
71#if !defined(CONFIG_SOFTMMU)
blueswir184778502008-10-26 20:33:16 +000072#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000073 struct ucontext *uc = puc;
blueswir184778502008-10-26 20:33:16 +000074#elif defined(__OpenBSD__)
75 struct sigcontext *uc = puc;
76#endif
bellardfbf9eeb2004-04-25 21:21:33 +000077#endif
78
79 env = env1;
80
81 /* XXX: restore cpu registers saved in host registers */
82
83#if !defined(CONFIG_SOFTMMU)
84 if (puc) {
85 /* XXX: use siglongjmp ? */
blueswir184778502008-10-26 20:33:16 +000086#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000087 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
blueswir184778502008-10-26 20:33:16 +000088#elif defined(__OpenBSD__)
89 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
90#endif
bellardfbf9eeb2004-04-25 21:21:33 +000091 }
92#endif
93 longjmp(env->jmp_env, 1);
94}
95
pbrook2e70f6e2008-06-29 01:03:05 +000096/* Execute the code without caching the generated code. An interpreter
97 could be used if available. */
98static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
99{
100 unsigned long next_tb;
101 TranslationBlock *tb;
102
103 /* Should never happen.
104 We only end up here when an existing TB is too long. */
105 if (max_cycles > CF_COUNT_MASK)
106 max_cycles = CF_COUNT_MASK;
107
108 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
109 max_cycles);
110 env->current_tb = tb;
111 /* execute the generated code */
112 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
113
114 if ((next_tb & 3) == 2) {
115 /* Restore PC. This may happen if async event occurs before
116 the TB starts executing. */
117 CPU_PC_FROM_TB(env, tb);
118 }
119 tb_phys_invalidate(tb, -1);
120 tb_free(tb);
121}
122
bellard8a40a182005-11-20 10:35:40 +0000123static TranslationBlock *tb_find_slow(target_ulong pc,
124 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000125 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000126{
127 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +0000128 unsigned int h;
129 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
ths3b46e622007-09-17 08:09:54 +0000130
bellard8a40a182005-11-20 10:35:40 +0000131 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000132
bellard8a40a182005-11-20 10:35:40 +0000133 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000134
bellard8a40a182005-11-20 10:35:40 +0000135 /* find translated block using physical mappings */
136 phys_pc = get_phys_addr_code(env, pc);
137 phys_page1 = phys_pc & TARGET_PAGE_MASK;
138 phys_page2 = -1;
139 h = tb_phys_hash_func(phys_pc);
140 ptb1 = &tb_phys_hash[h];
141 for(;;) {
142 tb = *ptb1;
143 if (!tb)
144 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000145 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000146 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000147 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000148 tb->flags == flags) {
149 /* check next page if needed */
150 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000151 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000152 TARGET_PAGE_SIZE;
153 phys_page2 = get_phys_addr_code(env, virt_page2);
154 if (tb->page_addr[1] == phys_page2)
155 goto found;
156 } else {
157 goto found;
158 }
159 }
160 ptb1 = &tb->phys_hash_next;
161 }
162 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000163 /* if no translated code available, then translate it now */
164 tb = tb_gen_code(env, pc, cs_base, flags, 0);
ths3b46e622007-09-17 08:09:54 +0000165
bellard8a40a182005-11-20 10:35:40 +0000166 found:
bellard8a40a182005-11-20 10:35:40 +0000167 /* we add the TB in the virtual pc hash table */
168 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
bellard8a40a182005-11-20 10:35:40 +0000169 return tb;
170}
171
172static inline TranslationBlock *tb_find_fast(void)
173{
174 TranslationBlock *tb;
175 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000176 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000177
178 /* we record a subset of the CPU state. It will
179 always be the same before a given translated block
180 is executed. */
181#if defined(TARGET_I386)
182 flags = env->hflags;
183 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
184 cs_base = env->segs[R_CS].base;
185 pc = cs_base + env->eip;
186#elif defined(TARGET_ARM)
187 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000188 | (env->vfp.vec_stride << 4);
189 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
190 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000191 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
192 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000193 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000194 cs_base = 0;
195 pc = env->regs[15];
196#elif defined(TARGET_SPARC)
197#ifdef TARGET_SPARC64
blueswir12cade6a2008-07-17 12:53:05 +0000198 // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
199 flags = ((env->pstate & PS_AM) << 2)
200 | (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
bellarda80dde02006-06-26 19:53:29 +0000201 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000202#else
blueswir16d5f2372007-11-07 17:03:37 +0000203 // FPU enable . Supervisor
204 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000205#endif
206 cs_base = env->npc;
207 pc = env->pc;
208#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000209 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000210 cs_base = 0;
211 pc = env->nip;
212#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000213 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000214 cs_base = 0;
thsb5dc7732008-06-27 10:02:35 +0000215 pc = env->active_tc.PC;
pbrooke6e59062006-10-22 00:18:54 +0000216#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000217 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
218 | (env->sr & SR_S) /* Bit 13 */
219 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000220 cs_base = 0;
221 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000222#elif defined(TARGET_SH4)
aurel32fe255912008-09-15 08:49:15 +0000223 flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
224 | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */
225 | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */
226 | (env->sr & (SR_MD | SR_RB)); /* Bits 29-30 */
ths823029f2007-12-02 06:10:04 +0000227 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000228 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000229#elif defined(TARGET_ALPHA)
230 flags = env->ps;
231 cs_base = 0;
232 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000233#elif defined(TARGET_CRIS)
edgar_igla1aebcb2008-10-07 22:48:41 +0000234 flags = env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG | X_FLAG);
edgar_iglcf1d97f2008-05-13 10:59:14 +0000235 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000236 cs_base = 0;
237 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000238#else
239#error unsupported CPU
240#endif
bellardbce61842008-02-01 22:18:51 +0000241 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000242 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
243 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000244 tb = tb_find_slow(pc, cs_base, flags);
245 }
246 return tb;
247}
248
bellard7d132992003-03-06 23:23:54 +0000249/* main execution loop */
250
bellarde4533c72003-06-15 19:51:39 +0000251int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000252{
pbrook1057eaa2007-02-04 13:37:44 +0000253#define DECLARE_HOST_REGS 1
254#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000255 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000256 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000257 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000258 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000259
thsbfed01f2007-06-03 17:44:37 +0000260 if (cpu_halted(env1) == EXCP_HALTED)
261 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000262
ths5fafdf22007-09-16 21:08:06 +0000263 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000264
bellard7d132992003-03-06 23:23:54 +0000265 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000266#define SAVE_HOST_REGS 1
267#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000268 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000269
bellard0d1a29f2004-10-12 22:01:28 +0000270 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000271#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000272 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000273 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
274 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000275 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000276 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000277#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000278#elif defined(TARGET_M68K)
279 env->cc_op = CC_OP_FLAGS;
280 env->cc_dest = env->sr & 0xf;
281 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000282#elif defined(TARGET_ALPHA)
283#elif defined(TARGET_ARM)
284#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000285#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000286#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000287#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000288 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000289#else
290#error unsupported target CPU
291#endif
bellard3fb2ded2003-06-24 13:22:59 +0000292 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000293
bellard7d132992003-03-06 23:23:54 +0000294 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000295 for(;;) {
296 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000297 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000298 /* if an exception is pending, we execute it here */
299 if (env->exception_index >= 0) {
300 if (env->exception_index >= EXCP_INTERRUPT) {
301 /* exit request from the cpu execution loop */
302 ret = env->exception_index;
303 break;
304 } else if (env->user_mode_only) {
305 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000306 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000307 loop */
bellard83479e72003-06-25 16:12:37 +0000308#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000309 do_interrupt_user(env->exception_index,
310 env->exception_is_int,
311 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000312 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000313 /* successfully delivered */
314 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000315#endif
bellard3fb2ded2003-06-24 13:22:59 +0000316 ret = env->exception_index;
317 break;
318 } else {
bellard83479e72003-06-25 16:12:37 +0000319#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000320 /* simulate a real cpu exception. On i386, it can
321 trigger new exceptions, but we do not handle
322 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000323 do_interrupt(env->exception_index,
324 env->exception_is_int,
325 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000326 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000327 /* successfully delivered */
328 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000329#elif defined(TARGET_PPC)
330 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000331#elif defined(TARGET_MIPS)
332 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000333#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000334 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000335#elif defined(TARGET_ARM)
336 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000337#elif defined(TARGET_SH4)
338 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000339#elif defined(TARGET_ALPHA)
340 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000341#elif defined(TARGET_CRIS)
342 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000343#elif defined(TARGET_M68K)
344 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000345#endif
bellard3fb2ded2003-06-24 13:22:59 +0000346 }
347 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000348 }
bellard9df217a2005-02-10 22:05:51 +0000349#ifdef USE_KQEMU
350 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
351 int ret;
352 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
353 ret = kqemu_cpu_exec(env);
354 /* put eflags in CPU temporary format */
355 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
356 DF = 1 - (2 * ((env->eflags >> 10) & 1));
357 CC_OP = CC_OP_EFLAGS;
358 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
359 if (ret == 1) {
360 /* exception */
361 longjmp(env->jmp_env, 1);
362 } else if (ret == 2) {
363 /* softmmu execution needed */
364 } else {
365 if (env->interrupt_request != 0) {
366 /* hardware interrupt will be executed just after */
367 } else {
368 /* otherwise, we restart */
369 longjmp(env->jmp_env, 1);
370 }
371 }
bellard9de5e442003-03-23 16:49:39 +0000372 }
bellard9df217a2005-02-10 22:05:51 +0000373#endif
374
aliguori7ba1e612008-11-05 16:04:33 +0000375 if (kvm_enabled()) {
376 int ret;
377 ret = kvm_cpu_exec(env);
378 if ((env->interrupt_request & CPU_INTERRUPT_EXIT)) {
379 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
380 env->exception_index = EXCP_INTERRUPT;
381 cpu_loop_exit();
382 } else if (env->halted) {
383 cpu_loop_exit();
384 } else
385 longjmp(env->jmp_env, 1);
386 }
387
blueswir1b5fc09a2008-05-04 06:38:18 +0000388 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000389 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000390 interrupt_request = env->interrupt_request;
ths551bd272008-07-03 17:57:36 +0000391 if (unlikely(interrupt_request) &&
bellarddb620f42008-06-04 17:02:19 +0000392 likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
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)
bellarddb620f42008-06-04 17:02:19 +0000408 if (env->hflags2 & HF2_GIF_MASK) {
409 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
410 !(env->hflags & HF_SMM_MASK)) {
411 svm_check_intercept(SVM_EXIT_SMI);
412 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
413 do_smm_enter();
414 next_tb = 0;
415 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
416 !(env->hflags2 & HF2_NMI_MASK)) {
417 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
418 env->hflags2 |= HF2_NMI_MASK;
419 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
420 next_tb = 0;
421 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
422 (((env->hflags2 & HF2_VINTR_MASK) &&
423 (env->hflags2 & HF2_HIF_MASK)) ||
424 (!(env->hflags2 & HF2_VINTR_MASK) &&
425 (env->eflags & IF_MASK &&
426 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
427 int intno;
428 svm_check_intercept(SVM_EXIT_INTR);
429 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
430 intno = cpu_get_pic_interrupt(env);
431 if (loglevel & CPU_LOG_TB_IN_ASM) {
432 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
433 }
434 do_interrupt(intno, 0, 0, 0, 1);
435 /* ensure that no TB jump will be modified as
436 the program flow was changed */
437 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000438#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000439 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
440 (env->eflags & IF_MASK) &&
441 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
442 int intno;
443 /* FIXME: this should respect TPR */
444 svm_check_intercept(SVM_EXIT_VINTR);
445 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
446 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
447 if (loglevel & CPU_LOG_TB_IN_ASM)
448 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
449 do_interrupt(intno, 0, 0, 0, 1);
450 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000451#endif
bellarddb620f42008-06-04 17:02:19 +0000452 }
bellard68a79312003-06-30 13:12:32 +0000453 }
bellardce097762004-01-04 23:53:18 +0000454#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000455#if 0
456 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
457 cpu_ppc_reset(env);
458 }
459#endif
j_mayer47103572007-03-30 09:38:04 +0000460 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000461 ppc_hw_interrupt(env);
462 if (env->pending_interrupts == 0)
463 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000464 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000465 }
bellard6af0bf92005-07-02 14:58:51 +0000466#elif defined(TARGET_MIPS)
467 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000468 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000469 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000470 !(env->CP0_Status & (1 << CP0St_EXL)) &&
471 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000472 !(env->hflags & MIPS_HFLAG_DM)) {
473 /* Raise it */
474 env->exception_index = EXCP_EXT_INTERRUPT;
475 env->error_code = 0;
476 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000477 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000478 }
bellarde95c8d52004-09-30 22:22:08 +0000479#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000480 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
481 (env->psret != 0)) {
482 int pil = env->interrupt_index & 15;
483 int type = env->interrupt_index & 0xf0;
484
485 if (((type == TT_EXTINT) &&
486 (pil == 15 || pil > env->psrpil)) ||
487 type != TT_EXTINT) {
488 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000489 env->exception_index = env->interrupt_index;
490 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000491 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000492#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
493 cpu_check_irqs(env);
494#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000495 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000496 }
bellarde95c8d52004-09-30 22:22:08 +0000497 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
498 //do_interrupt(0, 0, 0, 0, 0);
499 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000500 }
bellardb5ff1b32005-11-26 10:38:39 +0000501#elif defined(TARGET_ARM)
502 if (interrupt_request & CPU_INTERRUPT_FIQ
503 && !(env->uncached_cpsr & CPSR_F)) {
504 env->exception_index = EXCP_FIQ;
505 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000506 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000507 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000508 /* ARMv7-M interrupt return works by loading a magic value
509 into the PC. On real hardware the load causes the
510 return to occur. The qemu implementation performs the
511 jump normally, then does the exception return when the
512 CPU tries to execute code at the magic address.
513 This will cause the magic PC value to be pushed to
514 the stack if an interrupt occured at the wrong time.
515 We avoid this by disabling interrupts when
516 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000517 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000518 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
519 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000520 env->exception_index = EXCP_IRQ;
521 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000522 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000523 }
bellardfdf9b3e2006-04-27 21:07:38 +0000524#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000525 if (interrupt_request & CPU_INTERRUPT_HARD) {
526 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000527 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000528 }
j_mayereddf68a2007-04-05 07:22:49 +0000529#elif defined(TARGET_ALPHA)
530 if (interrupt_request & CPU_INTERRUPT_HARD) {
531 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000532 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000533 }
thsf1ccf902007-10-08 13:16:14 +0000534#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000535 if (interrupt_request & CPU_INTERRUPT_HARD
536 && (env->pregs[PR_CCS] & I_FLAG)) {
537 env->exception_index = EXCP_IRQ;
538 do_interrupt(env);
539 next_tb = 0;
540 }
541 if (interrupt_request & CPU_INTERRUPT_NMI
542 && (env->pregs[PR_CCS] & M_FLAG)) {
543 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000544 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000545 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000546 }
pbrook06338792007-05-23 19:58:11 +0000547#elif defined(TARGET_M68K)
548 if (interrupt_request & CPU_INTERRUPT_HARD
549 && ((env->sr & SR_I) >> SR_I_SHIFT)
550 < env->pending_level) {
551 /* Real hardware gets the interrupt vector via an
552 IACK cycle at this point. Current emulated
553 hardware doesn't rely on this, so we
554 provide/save the vector when the interrupt is
555 first signalled. */
556 env->exception_index = env->pending_vector;
557 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000558 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000559 }
bellard68a79312003-06-30 13:12:32 +0000560#endif
bellard9d050952006-05-22 22:03:52 +0000561 /* Don't use the cached interupt_request value,
562 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000563 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000564 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
565 /* ensure that no TB jump will be modified as
566 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000567 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000568 }
bellard68a79312003-06-30 13:12:32 +0000569 if (interrupt_request & CPU_INTERRUPT_EXIT) {
570 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
571 env->exception_index = EXCP_INTERRUPT;
572 cpu_loop_exit();
573 }
bellard3fb2ded2003-06-24 13:22:59 +0000574 }
575#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000576 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000577 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000578 regs_to_env();
579#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000580 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000581 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000582 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000583#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000584 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000585#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000586 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000587#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000588 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000589#elif defined(TARGET_M68K)
590 cpu_m68k_flush_flags(env, env->cc_op);
591 env->cc_op = CC_OP_FLAGS;
592 env->sr = (env->sr & 0xffe0)
593 | env->cc_dest | (env->cc_x << 4);
594 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000595#elif defined(TARGET_MIPS)
596 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000597#elif defined(TARGET_SH4)
598 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000599#elif defined(TARGET_ALPHA)
600 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000601#elif defined(TARGET_CRIS)
602 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000603#else
ths5fafdf22007-09-16 21:08:06 +0000604#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000605#endif
bellard3fb2ded2003-06-24 13:22:59 +0000606 }
bellard7d132992003-03-06 23:23:54 +0000607#endif
pbrookd5975362008-06-07 20:50:51 +0000608 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000609 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000610 /* Note: we do it here to avoid a gcc bug on Mac OS X when
611 doing it in tb_find_slow */
612 if (tb_invalidated_flag) {
613 /* as some TB could have been invalidated because
614 of memory exceptions while generating the code, we
615 must recompute the hash index here */
616 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000617 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000618 }
bellard9d27abd2003-05-10 13:13:54 +0000619#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000620 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000621 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
622 (long)tb->tc_ptr, tb->pc,
623 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000624 }
bellard9d27abd2003-05-10 13:13:54 +0000625#endif
bellard8a40a182005-11-20 10:35:40 +0000626 /* see if we can patch the calling TB. When the TB
627 spans two pages, we cannot safely do a direct
628 jump. */
bellardc27004e2005-01-03 23:35:10 +0000629 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000630 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000631#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000632 (env->kqemu_enabled != 2) &&
633#endif
bellardec6338b2007-11-08 14:25:03 +0000634 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000635 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000636 }
bellardc27004e2005-01-03 23:35:10 +0000637 }
pbrookd5975362008-06-07 20:50:51 +0000638 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000639 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000640
641 /* cpu_interrupt might be called while translating the
642 TB, but before it is linked into a potentially
643 infinite loop and becomes env->current_tb. Avoid
644 starting execution if there is a pending interrupt. */
645 if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
646 env->current_tb = NULL;
647
pbrook2e70f6e2008-06-29 01:03:05 +0000648 while (env->current_tb) {
649 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000650 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000651#if defined(__sparc__) && !defined(HOST_SOLARIS)
652#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000653 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000654#define env cpu_single_env
655#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000656 next_tb = tcg_qemu_tb_exec(tc_ptr);
657 env->current_tb = NULL;
658 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000659 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000660 int insns_left;
661 tb = (TranslationBlock *)(long)(next_tb & ~3);
662 /* Restore PC. */
663 CPU_PC_FROM_TB(env, tb);
664 insns_left = env->icount_decr.u32;
665 if (env->icount_extra && insns_left >= 0) {
666 /* Refill decrementer and continue execution. */
667 env->icount_extra += insns_left;
668 if (env->icount_extra > 0xffff) {
669 insns_left = 0xffff;
670 } else {
671 insns_left = env->icount_extra;
672 }
673 env->icount_extra -= insns_left;
674 env->icount_decr.u16.low = insns_left;
675 } else {
676 if (insns_left > 0) {
677 /* Execute remaining instructions. */
678 cpu_exec_nocache(insns_left, tb);
679 }
680 env->exception_index = EXCP_INTERRUPT;
681 next_tb = 0;
682 cpu_loop_exit();
683 }
684 }
685 }
bellard4cbf74b2003-08-10 21:48:43 +0000686 /* reset soft MMU for next block (it can currently
687 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000688#if defined(USE_KQEMU)
689#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
690 if (kqemu_is_ok(env) &&
691 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
692 cpu_loop_exit();
693 }
694#endif
ths50a518e2007-06-03 18:52:15 +0000695 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000696 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000697 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000698 }
bellard3fb2ded2003-06-24 13:22:59 +0000699 } /* for(;;) */
700
bellard7d132992003-03-06 23:23:54 +0000701
bellarde4533c72003-06-15 19:51:39 +0000702#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000703 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000704 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000705#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000706 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000707#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000708#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000709#elif defined(TARGET_M68K)
710 cpu_m68k_flush_flags(env, env->cc_op);
711 env->cc_op = CC_OP_FLAGS;
712 env->sr = (env->sr & 0xffe0)
713 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000714#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000715#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000716#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000717#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000718 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000719#else
720#error unsupported target CPU
721#endif
pbrook1057eaa2007-02-04 13:37:44 +0000722
723 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000724#include "hostregs_helper.h"
725
bellard6a00d602005-11-21 23:25:50 +0000726 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000727 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000728 return ret;
729}
bellard6dbad632003-03-16 18:05:05 +0000730
bellardfbf9eeb2004-04-25 21:21:33 +0000731/* must only be called from the generated code as an exception can be
732 generated */
733void tb_invalidate_page_range(target_ulong start, target_ulong end)
734{
bellarddc5d0b32004-06-22 18:43:30 +0000735 /* XXX: cannot enable it yet because it yields to MMU exception
736 where NIP != read address on PowerPC */
737#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000738 target_ulong phys_addr;
739 phys_addr = get_phys_addr_code(env, start);
740 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000741#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000742}
743
bellard1a18c712003-10-30 01:07:51 +0000744#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000745
bellard6dbad632003-03-16 18:05:05 +0000746void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
747{
748 CPUX86State *saved_env;
749
750 saved_env = env;
751 env = s;
bellarda412ac52003-07-26 18:01:40 +0000752 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000753 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000754 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000755 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000756 } else {
bellard5d975592008-05-12 22:05:33 +0000757 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000758 }
bellard6dbad632003-03-16 18:05:05 +0000759 env = saved_env;
760}
bellard9de5e442003-03-23 16:49:39 +0000761
bellard6f12a2a2007-11-11 22:16:56 +0000762void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000763{
764 CPUX86State *saved_env;
765
766 saved_env = env;
767 env = s;
ths3b46e622007-09-17 08:09:54 +0000768
bellard6f12a2a2007-11-11 22:16:56 +0000769 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000770
771 env = saved_env;
772}
773
bellard6f12a2a2007-11-11 22:16:56 +0000774void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000775{
776 CPUX86State *saved_env;
777
778 saved_env = env;
779 env = s;
ths3b46e622007-09-17 08:09:54 +0000780
bellard6f12a2a2007-11-11 22:16:56 +0000781 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000782
783 env = saved_env;
784}
785
bellarde4533c72003-06-15 19:51:39 +0000786#endif /* TARGET_I386 */
787
bellard67b915a2004-03-31 23:37:16 +0000788#if !defined(CONFIG_SOFTMMU)
789
bellard3fb2ded2003-06-24 13:22:59 +0000790#if defined(TARGET_I386)
791
bellardb56dad12003-05-08 15:38:04 +0000792/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000793 the effective address of the memory exception. 'is_write' is 1 if a
794 write caused the exception and otherwise 0'. 'old_set' is the
795 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000796static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000797 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000798 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000799{
bellarda513fe12003-05-27 23:29:48 +0000800 TranslationBlock *tb;
801 int ret;
bellard68a79312003-06-30 13:12:32 +0000802
bellard83479e72003-06-25 16:12:37 +0000803 if (cpu_single_env)
804 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000805#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000806 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000807 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000808#endif
bellard25eb4482003-05-14 21:50:54 +0000809 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000810 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000811 return 1;
812 }
bellardfbf9eeb2004-04-25 21:21:33 +0000813
bellard3fb2ded2003-06-24 13:22:59 +0000814 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000815 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000816 if (ret < 0)
817 return 0; /* not an MMU fault */
818 if (ret == 0)
819 return 1; /* the MMU fault was handled without causing real CPU fault */
820 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000821 tb = tb_find_pc(pc);
822 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000823 /* the PC is inside the translated code. It means that we have
824 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000825 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000826 }
bellard4cbf74b2003-08-10 21:48:43 +0000827 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000828#if 0
ths5fafdf22007-09-16 21:08:06 +0000829 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000830 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000831#endif
bellard4cbf74b2003-08-10 21:48:43 +0000832 /* we restore the process signal mask as the sigreturn should
833 do it (XXX: use sigsetjmp) */
834 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000835 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000836 } else {
837 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000838 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000839 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000840 }
bellard3fb2ded2003-06-24 13:22:59 +0000841 /* never comes here */
842 return 1;
843}
844
bellarde4533c72003-06-15 19:51:39 +0000845#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000846static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000847 int is_write, sigset_t *old_set,
848 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000849{
bellard68016c62005-02-07 23:12:27 +0000850 TranslationBlock *tb;
851 int ret;
852
853 if (cpu_single_env)
854 env = cpu_single_env; /* XXX: find a correct solution for multithread */
855#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000856 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000857 pc, address, is_write, *(unsigned long *)old_set);
858#endif
bellard9f0777e2005-02-02 20:42:01 +0000859 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000860 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000861 return 1;
862 }
bellard68016c62005-02-07 23:12:27 +0000863 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000864 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000865 if (ret < 0)
866 return 0; /* not an MMU fault */
867 if (ret == 0)
868 return 1; /* the MMU fault was handled without causing real CPU fault */
869 /* now we have a real cpu fault */
870 tb = tb_find_pc(pc);
871 if (tb) {
872 /* the PC is inside the translated code. It means that we have
873 a virtual CPU fault */
874 cpu_restore_state(tb, env, pc, puc);
875 }
876 /* we restore the process signal mask as the sigreturn should
877 do it (XXX: use sigsetjmp) */
878 sigprocmask(SIG_SETMASK, old_set, NULL);
879 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000880 /* never comes here */
881 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000882}
bellard93ac68b2003-09-30 20:57:29 +0000883#elif defined(TARGET_SPARC)
884static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000885 int is_write, sigset_t *old_set,
886 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000887{
bellard68016c62005-02-07 23:12:27 +0000888 TranslationBlock *tb;
889 int ret;
890
891 if (cpu_single_env)
892 env = cpu_single_env; /* XXX: find a correct solution for multithread */
893#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000894 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000895 pc, address, is_write, *(unsigned long *)old_set);
896#endif
bellardb453b702004-01-04 15:45:21 +0000897 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000898 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000899 return 1;
900 }
bellard68016c62005-02-07 23:12:27 +0000901 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000902 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000903 if (ret < 0)
904 return 0; /* not an MMU fault */
905 if (ret == 0)
906 return 1; /* the MMU fault was handled without causing real CPU fault */
907 /* now we have a real cpu fault */
908 tb = tb_find_pc(pc);
909 if (tb) {
910 /* the PC is inside the translated code. It means that we have
911 a virtual CPU fault */
912 cpu_restore_state(tb, env, pc, puc);
913 }
914 /* we restore the process signal mask as the sigreturn should
915 do it (XXX: use sigsetjmp) */
916 sigprocmask(SIG_SETMASK, old_set, NULL);
917 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000918 /* never comes here */
919 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000920}
bellard67867302003-11-23 17:05:30 +0000921#elif defined (TARGET_PPC)
922static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000923 int is_write, sigset_t *old_set,
924 void *puc)
bellard67867302003-11-23 17:05:30 +0000925{
926 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000927 int ret;
ths3b46e622007-09-17 08:09:54 +0000928
bellard67867302003-11-23 17:05:30 +0000929 if (cpu_single_env)
930 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000931#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000932 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000933 pc, address, is_write, *(unsigned long *)old_set);
934#endif
935 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000936 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000937 return 1;
938 }
939
bellardce097762004-01-04 23:53:18 +0000940 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000941 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000942 if (ret < 0)
943 return 0; /* not an MMU fault */
944 if (ret == 0)
945 return 1; /* the MMU fault was handled without causing real CPU fault */
946
bellard67867302003-11-23 17:05:30 +0000947 /* now we have a real cpu fault */
948 tb = tb_find_pc(pc);
949 if (tb) {
950 /* the PC is inside the translated code. It means that we have
951 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000952 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000953 }
bellardce097762004-01-04 23:53:18 +0000954 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000955#if 0
ths5fafdf22007-09-16 21:08:06 +0000956 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000957 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000958#endif
959 /* we restore the process signal mask as the sigreturn should
960 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000961 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000962 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000963 } else {
964 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000965 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000966 }
bellard67867302003-11-23 17:05:30 +0000967 /* never comes here */
968 return 1;
969}
bellard6af0bf92005-07-02 14:58:51 +0000970
pbrooke6e59062006-10-22 00:18:54 +0000971#elif defined(TARGET_M68K)
972static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
973 int is_write, sigset_t *old_set,
974 void *puc)
975{
976 TranslationBlock *tb;
977 int ret;
978
979 if (cpu_single_env)
980 env = cpu_single_env; /* XXX: find a correct solution for multithread */
981#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000982 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000983 pc, address, is_write, *(unsigned long *)old_set);
984#endif
985 /* XXX: locking issue */
986 if (is_write && page_unprotect(address, pc, puc)) {
987 return 1;
988 }
989 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000990 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000991 if (ret < 0)
992 return 0; /* not an MMU fault */
993 if (ret == 0)
994 return 1; /* the MMU fault was handled without causing real CPU fault */
995 /* now we have a real cpu fault */
996 tb = tb_find_pc(pc);
997 if (tb) {
998 /* the PC is inside the translated code. It means that we have
999 a virtual CPU fault */
1000 cpu_restore_state(tb, env, pc, puc);
1001 }
1002 /* we restore the process signal mask as the sigreturn should
1003 do it (XXX: use sigsetjmp) */
1004 sigprocmask(SIG_SETMASK, old_set, NULL);
1005 cpu_loop_exit();
1006 /* never comes here */
1007 return 1;
1008}
1009
bellard6af0bf92005-07-02 14:58:51 +00001010#elif defined (TARGET_MIPS)
1011static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1012 int is_write, sigset_t *old_set,
1013 void *puc)
1014{
1015 TranslationBlock *tb;
1016 int ret;
ths3b46e622007-09-17 08:09:54 +00001017
bellard6af0bf92005-07-02 14:58:51 +00001018 if (cpu_single_env)
1019 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1020#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001021 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001022 pc, address, is_write, *(unsigned long *)old_set);
1023#endif
1024 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001025 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001026 return 1;
1027 }
1028
1029 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001030 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001031 if (ret < 0)
1032 return 0; /* not an MMU fault */
1033 if (ret == 0)
1034 return 1; /* the MMU fault was handled without causing real CPU fault */
1035
1036 /* now we have a real cpu fault */
1037 tb = tb_find_pc(pc);
1038 if (tb) {
1039 /* the PC is inside the translated code. It means that we have
1040 a virtual CPU fault */
1041 cpu_restore_state(tb, env, pc, puc);
1042 }
1043 if (ret == 1) {
1044#if 0
ths5fafdf22007-09-16 21:08:06 +00001045 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001046 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001047#endif
1048 /* we restore the process signal mask as the sigreturn should
1049 do it (XXX: use sigsetjmp) */
1050 sigprocmask(SIG_SETMASK, old_set, NULL);
1051 do_raise_exception_err(env->exception_index, env->error_code);
1052 } else {
1053 /* activate soft MMU for this block */
1054 cpu_resume_from_signal(env, puc);
1055 }
1056 /* never comes here */
1057 return 1;
1058}
1059
bellardfdf9b3e2006-04-27 21:07:38 +00001060#elif defined (TARGET_SH4)
1061static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1062 int is_write, sigset_t *old_set,
1063 void *puc)
1064{
1065 TranslationBlock *tb;
1066 int ret;
ths3b46e622007-09-17 08:09:54 +00001067
bellardfdf9b3e2006-04-27 21:07:38 +00001068 if (cpu_single_env)
1069 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1070#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001071 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001072 pc, address, is_write, *(unsigned long *)old_set);
1073#endif
1074 /* XXX: locking issue */
1075 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1076 return 1;
1077 }
1078
1079 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001080 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001081 if (ret < 0)
1082 return 0; /* not an MMU fault */
1083 if (ret == 0)
1084 return 1; /* the MMU fault was handled without causing real CPU fault */
1085
1086 /* now we have a real cpu fault */
1087 tb = tb_find_pc(pc);
1088 if (tb) {
1089 /* the PC is inside the translated code. It means that we have
1090 a virtual CPU fault */
1091 cpu_restore_state(tb, env, pc, puc);
1092 }
bellardfdf9b3e2006-04-27 21:07:38 +00001093#if 0
ths5fafdf22007-09-16 21:08:06 +00001094 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001095 env->nip, env->error_code, tb);
1096#endif
1097 /* we restore the process signal mask as the sigreturn should
1098 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001099 sigprocmask(SIG_SETMASK, old_set, NULL);
1100 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001101 /* never comes here */
1102 return 1;
1103}
j_mayereddf68a2007-04-05 07:22:49 +00001104
1105#elif defined (TARGET_ALPHA)
1106static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1107 int is_write, sigset_t *old_set,
1108 void *puc)
1109{
1110 TranslationBlock *tb;
1111 int ret;
ths3b46e622007-09-17 08:09:54 +00001112
j_mayereddf68a2007-04-05 07:22:49 +00001113 if (cpu_single_env)
1114 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1115#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001116 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001117 pc, address, is_write, *(unsigned long *)old_set);
1118#endif
1119 /* XXX: locking issue */
1120 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1121 return 1;
1122 }
1123
1124 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001125 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001126 if (ret < 0)
1127 return 0; /* not an MMU fault */
1128 if (ret == 0)
1129 return 1; /* the MMU fault was handled without causing real CPU fault */
1130
1131 /* now we have a real cpu fault */
1132 tb = tb_find_pc(pc);
1133 if (tb) {
1134 /* the PC is inside the translated code. It means that we have
1135 a virtual CPU fault */
1136 cpu_restore_state(tb, env, pc, puc);
1137 }
1138#if 0
ths5fafdf22007-09-16 21:08:06 +00001139 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001140 env->nip, env->error_code, tb);
1141#endif
1142 /* we restore the process signal mask as the sigreturn should
1143 do it (XXX: use sigsetjmp) */
1144 sigprocmask(SIG_SETMASK, old_set, NULL);
1145 cpu_loop_exit();
1146 /* never comes here */
1147 return 1;
1148}
thsf1ccf902007-10-08 13:16:14 +00001149#elif defined (TARGET_CRIS)
1150static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1151 int is_write, sigset_t *old_set,
1152 void *puc)
1153{
1154 TranslationBlock *tb;
1155 int ret;
1156
1157 if (cpu_single_env)
1158 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1159#if defined(DEBUG_SIGNAL)
1160 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1161 pc, address, is_write, *(unsigned long *)old_set);
1162#endif
1163 /* XXX: locking issue */
1164 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1165 return 1;
1166 }
1167
1168 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001169 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001170 if (ret < 0)
1171 return 0; /* not an MMU fault */
1172 if (ret == 0)
1173 return 1; /* the MMU fault was handled without causing real CPU fault */
1174
1175 /* now we have a real cpu fault */
1176 tb = tb_find_pc(pc);
1177 if (tb) {
1178 /* the PC is inside the translated code. It means that we have
1179 a virtual CPU fault */
1180 cpu_restore_state(tb, env, pc, puc);
1181 }
thsf1ccf902007-10-08 13:16:14 +00001182 /* we restore the process signal mask as the sigreturn should
1183 do it (XXX: use sigsetjmp) */
1184 sigprocmask(SIG_SETMASK, old_set, NULL);
1185 cpu_loop_exit();
1186 /* never comes here */
1187 return 1;
1188}
1189
bellarde4533c72003-06-15 19:51:39 +00001190#else
1191#error unsupported target CPU
1192#endif
bellard9de5e442003-03-23 16:49:39 +00001193
bellard2b413142003-05-14 23:01:10 +00001194#if defined(__i386__)
1195
bellardd8ecc0b2007-02-05 21:41:46 +00001196#if defined(__APPLE__)
1197# include <sys/ucontext.h>
1198
1199# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1200# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1201# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1202#else
1203# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1204# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1205# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1206#endif
1207
ths5fafdf22007-09-16 21:08:06 +00001208int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001209 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001210{
ths5a7b5422007-01-31 12:16:51 +00001211 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001212 struct ucontext *uc = puc;
1213 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001214 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001215
bellardd691f662003-03-24 21:58:34 +00001216#ifndef REG_EIP
1217/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001218#define REG_EIP EIP
1219#define REG_ERR ERR
1220#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001221#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001222 pc = EIP_sig(uc);
1223 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001224 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1225 trapno == 0xe ?
1226 (ERROR_sig(uc) >> 1) & 1 : 0,
1227 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001228}
1229
bellardbc51c5c2004-03-17 23:46:04 +00001230#elif defined(__x86_64__)
1231
ths5a7b5422007-01-31 12:16:51 +00001232int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001233 void *puc)
1234{
ths5a7b5422007-01-31 12:16:51 +00001235 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001236 struct ucontext *uc = puc;
1237 unsigned long pc;
1238
1239 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001240 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1241 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001242 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1243 &uc->uc_sigmask, puc);
1244}
1245
bellard83fb7ad2004-07-05 21:25:26 +00001246#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001247
bellard83fb7ad2004-07-05 21:25:26 +00001248/***********************************************************************
1249 * signal context platform-specific definitions
1250 * From Wine
1251 */
1252#ifdef linux
1253/* All Registers access - only for local access */
1254# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1255/* Gpr Registers access */
1256# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1257# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1258# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1259# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1260# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1261# define LR_sig(context) REG_sig(link, context) /* Link register */
1262# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1263/* Float Registers access */
1264# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1265# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1266/* Exception Registers access */
1267# define DAR_sig(context) REG_sig(dar, context)
1268# define DSISR_sig(context) REG_sig(dsisr, context)
1269# define TRAP_sig(context) REG_sig(trap, context)
1270#endif /* linux */
1271
1272#ifdef __APPLE__
1273# include <sys/ucontext.h>
1274typedef struct ucontext SIGCONTEXT;
1275/* All Registers access - only for local access */
1276# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1277# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1278# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1279# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1280/* Gpr Registers access */
1281# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1282# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1283# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1284# define CTR_sig(context) REG_sig(ctr, context)
1285# define XER_sig(context) REG_sig(xer, context) /* Link register */
1286# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1287# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1288/* Float Registers access */
1289# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1290# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1291/* Exception Registers access */
1292# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1293# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1294# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1295#endif /* __APPLE__ */
1296
ths5fafdf22007-09-16 21:08:06 +00001297int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001298 void *puc)
bellard2b413142003-05-14 23:01:10 +00001299{
ths5a7b5422007-01-31 12:16:51 +00001300 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001301 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001302 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001303 int is_write;
1304
bellard83fb7ad2004-07-05 21:25:26 +00001305 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001306 is_write = 0;
1307#if 0
1308 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001309 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001310 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001311#else
bellard83fb7ad2004-07-05 21:25:26 +00001312 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001313 is_write = 1;
1314#endif
ths5fafdf22007-09-16 21:08:06 +00001315 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001316 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001317}
bellard2b413142003-05-14 23:01:10 +00001318
bellard2f87c602003-06-02 20:38:09 +00001319#elif defined(__alpha__)
1320
ths5fafdf22007-09-16 21:08:06 +00001321int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001322 void *puc)
1323{
ths5a7b5422007-01-31 12:16:51 +00001324 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001325 struct ucontext *uc = puc;
1326 uint32_t *pc = uc->uc_mcontext.sc_pc;
1327 uint32_t insn = *pc;
1328 int is_write = 0;
1329
bellard8c6939c2003-06-09 15:28:00 +00001330 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001331 switch (insn >> 26) {
1332 case 0x0d: // stw
1333 case 0x0e: // stb
1334 case 0x0f: // stq_u
1335 case 0x24: // stf
1336 case 0x25: // stg
1337 case 0x26: // sts
1338 case 0x27: // stt
1339 case 0x2c: // stl
1340 case 0x2d: // stq
1341 case 0x2e: // stl_c
1342 case 0x2f: // stq_c
1343 is_write = 1;
1344 }
1345
ths5fafdf22007-09-16 21:08:06 +00001346 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001347 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001348}
bellard8c6939c2003-06-09 15:28:00 +00001349#elif defined(__sparc__)
1350
ths5fafdf22007-09-16 21:08:06 +00001351int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001352 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001353{
ths5a7b5422007-01-31 12:16:51 +00001354 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001355 int is_write;
1356 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001357#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001358 uint32_t *regs = (uint32_t *)(info + 1);
1359 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001360 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001361 unsigned long pc = regs[1];
1362#else
blueswir184778502008-10-26 20:33:16 +00001363#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001364 struct sigcontext *sc = puc;
1365 unsigned long pc = sc->sigc_regs.tpc;
1366 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001367#elif defined(__OpenBSD__)
1368 struct sigcontext *uc = puc;
1369 unsigned long pc = uc->sc_pc;
1370 void *sigmask = (void *)(long)uc->sc_mask;
1371#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001372#endif
1373
bellard8c6939c2003-06-09 15:28:00 +00001374 /* XXX: need kernel patch to get write flag faster */
1375 is_write = 0;
1376 insn = *(uint32_t *)pc;
1377 if ((insn >> 30) == 3) {
1378 switch((insn >> 19) & 0x3f) {
1379 case 0x05: // stb
1380 case 0x06: // sth
1381 case 0x04: // st
1382 case 0x07: // std
1383 case 0x24: // stf
1384 case 0x27: // stdf
1385 case 0x25: // stfsr
1386 is_write = 1;
1387 break;
1388 }
1389 }
ths5fafdf22007-09-16 21:08:06 +00001390 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001391 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001392}
1393
1394#elif defined(__arm__)
1395
ths5fafdf22007-09-16 21:08:06 +00001396int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001397 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001398{
ths5a7b5422007-01-31 12:16:51 +00001399 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001400 struct ucontext *uc = puc;
1401 unsigned long pc;
1402 int is_write;
ths3b46e622007-09-17 08:09:54 +00001403
blueswir148bbf112008-07-08 18:35:02 +00001404#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001405 pc = uc->uc_mcontext.gregs[R15];
1406#else
balrog4eee57f2008-05-06 14:47:19 +00001407 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001408#endif
bellard8c6939c2003-06-09 15:28:00 +00001409 /* XXX: compute is_write */
1410 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001411 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001412 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001413 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001414}
1415
bellard38e584a2003-08-10 22:14:22 +00001416#elif defined(__mc68000)
1417
ths5fafdf22007-09-16 21:08:06 +00001418int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001419 void *puc)
1420{
ths5a7b5422007-01-31 12:16:51 +00001421 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001422 struct ucontext *uc = puc;
1423 unsigned long pc;
1424 int is_write;
ths3b46e622007-09-17 08:09:54 +00001425
bellard38e584a2003-08-10 22:14:22 +00001426 pc = uc->uc_mcontext.gregs[16];
1427 /* XXX: compute is_write */
1428 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001429 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001430 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001431 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001432}
1433
bellardb8076a72005-04-07 22:20:31 +00001434#elif defined(__ia64)
1435
1436#ifndef __ISR_VALID
1437 /* This ought to be in <bits/siginfo.h>... */
1438# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001439#endif
1440
ths5a7b5422007-01-31 12:16:51 +00001441int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001442{
ths5a7b5422007-01-31 12:16:51 +00001443 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001444 struct ucontext *uc = puc;
1445 unsigned long ip;
1446 int is_write = 0;
1447
1448 ip = uc->uc_mcontext.sc_ip;
1449 switch (host_signum) {
1450 case SIGILL:
1451 case SIGFPE:
1452 case SIGSEGV:
1453 case SIGBUS:
1454 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001455 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001456 /* ISR.W (write-access) is bit 33: */
1457 is_write = (info->si_isr >> 33) & 1;
1458 break;
1459
1460 default:
1461 break;
1462 }
1463 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1464 is_write,
1465 &uc->uc_sigmask, puc);
1466}
1467
bellard90cb9492005-07-24 15:11:38 +00001468#elif defined(__s390__)
1469
ths5fafdf22007-09-16 21:08:06 +00001470int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001471 void *puc)
1472{
ths5a7b5422007-01-31 12:16:51 +00001473 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001474 struct ucontext *uc = puc;
1475 unsigned long pc;
1476 int is_write;
ths3b46e622007-09-17 08:09:54 +00001477
bellard90cb9492005-07-24 15:11:38 +00001478 pc = uc->uc_mcontext.psw.addr;
1479 /* XXX: compute is_write */
1480 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001481 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001482 is_write, &uc->uc_sigmask, puc);
1483}
1484
1485#elif defined(__mips__)
1486
ths5fafdf22007-09-16 21:08:06 +00001487int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001488 void *puc)
1489{
ths9617efe2007-05-08 21:05:55 +00001490 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001491 struct ucontext *uc = puc;
1492 greg_t pc = uc->uc_mcontext.pc;
1493 int is_write;
ths3b46e622007-09-17 08:09:54 +00001494
thsc4b89d12007-05-05 19:23:11 +00001495 /* XXX: compute is_write */
1496 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001497 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001498 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001499}
1500
aurel32f54b3f92008-04-12 20:14:54 +00001501#elif defined(__hppa__)
1502
1503int cpu_signal_handler(int host_signum, void *pinfo,
1504 void *puc)
1505{
1506 struct siginfo *info = pinfo;
1507 struct ucontext *uc = puc;
1508 unsigned long pc;
1509 int is_write;
1510
1511 pc = uc->uc_mcontext.sc_iaoq[0];
1512 /* FIXME: compute is_write */
1513 is_write = 0;
1514 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1515 is_write,
1516 &uc->uc_sigmask, puc);
1517}
1518
bellard2b413142003-05-14 23:01:10 +00001519#else
1520
bellard3fb2ded2003-06-24 13:22:59 +00001521#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001522
1523#endif
bellard67b915a2004-03-31 23:37:16 +00001524
1525#endif /* !defined(CONFIG_SOFTMMU) */