blob: 9265fc18eade6f2c96deae402296487d1d76d3d8 [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;
pbrooka7812ae2008-11-17 14:43:54 +0000348 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard9df217a2005-02-10 22:05:51 +0000349 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()) {
aliguoribecfc392008-11-10 15:55:14 +0000372 kvm_cpu_exec(env);
373 longjmp(env->jmp_env, 1);
aliguori7ba1e612008-11-05 16:04:33 +0000374 }
375
blueswir1b5fc09a2008-05-04 06:38:18 +0000376 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000377 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000378 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000379 if (unlikely(interrupt_request)) {
380 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
381 /* Mask out external interrupts for this step. */
382 interrupt_request &= ~(CPU_INTERRUPT_HARD |
383 CPU_INTERRUPT_FIQ |
384 CPU_INTERRUPT_SMI |
385 CPU_INTERRUPT_NMI);
386 }
pbrook6658ffb2007-03-16 23:58:11 +0000387 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
388 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
389 env->exception_index = EXCP_DEBUG;
390 cpu_loop_exit();
391 }
balroga90b7312007-05-01 01:28:01 +0000392#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000393 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000394 if (interrupt_request & CPU_INTERRUPT_HALT) {
395 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
396 env->halted = 1;
397 env->exception_index = EXCP_HLT;
398 cpu_loop_exit();
399 }
400#endif
bellard68a79312003-06-30 13:12:32 +0000401#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000402 if (env->hflags2 & HF2_GIF_MASK) {
403 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
404 !(env->hflags & HF_SMM_MASK)) {
405 svm_check_intercept(SVM_EXIT_SMI);
406 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
407 do_smm_enter();
408 next_tb = 0;
409 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
410 !(env->hflags2 & HF2_NMI_MASK)) {
411 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
412 env->hflags2 |= HF2_NMI_MASK;
413 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
414 next_tb = 0;
415 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
416 (((env->hflags2 & HF2_VINTR_MASK) &&
417 (env->hflags2 & HF2_HIF_MASK)) ||
418 (!(env->hflags2 & HF2_VINTR_MASK) &&
419 (env->eflags & IF_MASK &&
420 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
421 int intno;
422 svm_check_intercept(SVM_EXIT_INTR);
423 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
424 intno = cpu_get_pic_interrupt(env);
425 if (loglevel & CPU_LOG_TB_IN_ASM) {
426 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
427 }
428 do_interrupt(intno, 0, 0, 0, 1);
429 /* ensure that no TB jump will be modified as
430 the program flow was changed */
431 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000432#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000433 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
434 (env->eflags & IF_MASK) &&
435 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
436 int intno;
437 /* FIXME: this should respect TPR */
438 svm_check_intercept(SVM_EXIT_VINTR);
439 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
440 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
441 if (loglevel & CPU_LOG_TB_IN_ASM)
442 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
443 do_interrupt(intno, 0, 0, 0, 1);
444 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000445#endif
bellarddb620f42008-06-04 17:02:19 +0000446 }
bellard68a79312003-06-30 13:12:32 +0000447 }
bellardce097762004-01-04 23:53:18 +0000448#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000449#if 0
450 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
451 cpu_ppc_reset(env);
452 }
453#endif
j_mayer47103572007-03-30 09:38:04 +0000454 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000455 ppc_hw_interrupt(env);
456 if (env->pending_interrupts == 0)
457 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000458 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000459 }
bellard6af0bf92005-07-02 14:58:51 +0000460#elif defined(TARGET_MIPS)
461 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000462 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000463 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000464 !(env->CP0_Status & (1 << CP0St_EXL)) &&
465 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000466 !(env->hflags & MIPS_HFLAG_DM)) {
467 /* Raise it */
468 env->exception_index = EXCP_EXT_INTERRUPT;
469 env->error_code = 0;
470 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000471 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000472 }
bellarde95c8d52004-09-30 22:22:08 +0000473#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000474 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
475 (env->psret != 0)) {
476 int pil = env->interrupt_index & 15;
477 int type = env->interrupt_index & 0xf0;
478
479 if (((type == TT_EXTINT) &&
480 (pil == 15 || pil > env->psrpil)) ||
481 type != TT_EXTINT) {
482 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000483 env->exception_index = env->interrupt_index;
484 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000485 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000486#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
487 cpu_check_irqs(env);
488#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000489 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000490 }
bellarde95c8d52004-09-30 22:22:08 +0000491 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
492 //do_interrupt(0, 0, 0, 0, 0);
493 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000494 }
bellardb5ff1b32005-11-26 10:38:39 +0000495#elif defined(TARGET_ARM)
496 if (interrupt_request & CPU_INTERRUPT_FIQ
497 && !(env->uncached_cpsr & CPSR_F)) {
498 env->exception_index = EXCP_FIQ;
499 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000500 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000501 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000502 /* ARMv7-M interrupt return works by loading a magic value
503 into the PC. On real hardware the load causes the
504 return to occur. The qemu implementation performs the
505 jump normally, then does the exception return when the
506 CPU tries to execute code at the magic address.
507 This will cause the magic PC value to be pushed to
508 the stack if an interrupt occured at the wrong time.
509 We avoid this by disabling interrupts when
510 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000511 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000512 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
513 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000514 env->exception_index = EXCP_IRQ;
515 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000516 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000517 }
bellardfdf9b3e2006-04-27 21:07:38 +0000518#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000519 if (interrupt_request & CPU_INTERRUPT_HARD) {
520 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000521 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000522 }
j_mayereddf68a2007-04-05 07:22:49 +0000523#elif defined(TARGET_ALPHA)
524 if (interrupt_request & CPU_INTERRUPT_HARD) {
525 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000526 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000527 }
thsf1ccf902007-10-08 13:16:14 +0000528#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000529 if (interrupt_request & CPU_INTERRUPT_HARD
530 && (env->pregs[PR_CCS] & I_FLAG)) {
531 env->exception_index = EXCP_IRQ;
532 do_interrupt(env);
533 next_tb = 0;
534 }
535 if (interrupt_request & CPU_INTERRUPT_NMI
536 && (env->pregs[PR_CCS] & M_FLAG)) {
537 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000538 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000539 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000540 }
pbrook06338792007-05-23 19:58:11 +0000541#elif defined(TARGET_M68K)
542 if (interrupt_request & CPU_INTERRUPT_HARD
543 && ((env->sr & SR_I) >> SR_I_SHIFT)
544 < env->pending_level) {
545 /* Real hardware gets the interrupt vector via an
546 IACK cycle at this point. Current emulated
547 hardware doesn't rely on this, so we
548 provide/save the vector when the interrupt is
549 first signalled. */
550 env->exception_index = env->pending_vector;
551 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000552 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000553 }
bellard68a79312003-06-30 13:12:32 +0000554#endif
bellard9d050952006-05-22 22:03:52 +0000555 /* Don't use the cached interupt_request value,
556 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000557 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000558 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
559 /* ensure that no TB jump will be modified as
560 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000561 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000562 }
bellard68a79312003-06-30 13:12:32 +0000563 if (interrupt_request & CPU_INTERRUPT_EXIT) {
564 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
565 env->exception_index = EXCP_INTERRUPT;
566 cpu_loop_exit();
567 }
bellard3fb2ded2003-06-24 13:22:59 +0000568 }
569#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000570 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000571 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000572 regs_to_env();
573#if defined(TARGET_I386)
pbrooka7812ae2008-11-17 14:43:54 +0000574 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000575 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000576 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000577#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000578 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000579#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000580 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000581#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000582 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000583#elif defined(TARGET_M68K)
584 cpu_m68k_flush_flags(env, env->cc_op);
585 env->cc_op = CC_OP_FLAGS;
586 env->sr = (env->sr & 0xffe0)
587 | env->cc_dest | (env->cc_x << 4);
588 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000589#elif defined(TARGET_MIPS)
590 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000591#elif defined(TARGET_SH4)
592 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000593#elif defined(TARGET_ALPHA)
594 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000595#elif defined(TARGET_CRIS)
596 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000597#else
ths5fafdf22007-09-16 21:08:06 +0000598#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000599#endif
bellard3fb2ded2003-06-24 13:22:59 +0000600 }
bellard7d132992003-03-06 23:23:54 +0000601#endif
pbrookd5975362008-06-07 20:50:51 +0000602 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000603 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000604 /* Note: we do it here to avoid a gcc bug on Mac OS X when
605 doing it in tb_find_slow */
606 if (tb_invalidated_flag) {
607 /* as some TB could have been invalidated because
608 of memory exceptions while generating the code, we
609 must recompute the hash index here */
610 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000611 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000612 }
bellard9d27abd2003-05-10 13:13:54 +0000613#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000614 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000615 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
616 (long)tb->tc_ptr, tb->pc,
617 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000618 }
bellard9d27abd2003-05-10 13:13:54 +0000619#endif
bellard8a40a182005-11-20 10:35:40 +0000620 /* see if we can patch the calling TB. When the TB
621 spans two pages, we cannot safely do a direct
622 jump. */
bellardc27004e2005-01-03 23:35:10 +0000623 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000624 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000625#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000626 (env->kqemu_enabled != 2) &&
627#endif
bellardec6338b2007-11-08 14:25:03 +0000628 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000629 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000630 }
bellardc27004e2005-01-03 23:35:10 +0000631 }
pbrookd5975362008-06-07 20:50:51 +0000632 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000633 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000634
635 /* cpu_interrupt might be called while translating the
636 TB, but before it is linked into a potentially
637 infinite loop and becomes env->current_tb. Avoid
638 starting execution if there is a pending interrupt. */
639 if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
640 env->current_tb = NULL;
641
pbrook2e70f6e2008-06-29 01:03:05 +0000642 while (env->current_tb) {
643 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000644 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000645#if defined(__sparc__) && !defined(HOST_SOLARIS)
646#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000647 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000648#define env cpu_single_env
649#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000650 next_tb = tcg_qemu_tb_exec(tc_ptr);
651 env->current_tb = NULL;
652 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000653 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000654 int insns_left;
655 tb = (TranslationBlock *)(long)(next_tb & ~3);
656 /* Restore PC. */
657 CPU_PC_FROM_TB(env, tb);
658 insns_left = env->icount_decr.u32;
659 if (env->icount_extra && insns_left >= 0) {
660 /* Refill decrementer and continue execution. */
661 env->icount_extra += insns_left;
662 if (env->icount_extra > 0xffff) {
663 insns_left = 0xffff;
664 } else {
665 insns_left = env->icount_extra;
666 }
667 env->icount_extra -= insns_left;
668 env->icount_decr.u16.low = insns_left;
669 } else {
670 if (insns_left > 0) {
671 /* Execute remaining instructions. */
672 cpu_exec_nocache(insns_left, tb);
673 }
674 env->exception_index = EXCP_INTERRUPT;
675 next_tb = 0;
676 cpu_loop_exit();
677 }
678 }
679 }
bellard4cbf74b2003-08-10 21:48:43 +0000680 /* reset soft MMU for next block (it can currently
681 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000682#if defined(USE_KQEMU)
683#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
684 if (kqemu_is_ok(env) &&
685 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
686 cpu_loop_exit();
687 }
688#endif
ths50a518e2007-06-03 18:52:15 +0000689 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000690 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000691 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000692 }
bellard3fb2ded2003-06-24 13:22:59 +0000693 } /* for(;;) */
694
bellard7d132992003-03-06 23:23:54 +0000695
bellarde4533c72003-06-15 19:51:39 +0000696#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000697 /* restore flags in standard format */
pbrooka7812ae2008-11-17 14:43:54 +0000698 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000699#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000700 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000701#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000702#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000703#elif defined(TARGET_M68K)
704 cpu_m68k_flush_flags(env, env->cc_op);
705 env->cc_op = CC_OP_FLAGS;
706 env->sr = (env->sr & 0xffe0)
707 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000708#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000709#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000710#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000711#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000712 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000713#else
714#error unsupported target CPU
715#endif
pbrook1057eaa2007-02-04 13:37:44 +0000716
717 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000718#include "hostregs_helper.h"
719
bellard6a00d602005-11-21 23:25:50 +0000720 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000721 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000722 return ret;
723}
bellard6dbad632003-03-16 18:05:05 +0000724
bellardfbf9eeb2004-04-25 21:21:33 +0000725/* must only be called from the generated code as an exception can be
726 generated */
727void tb_invalidate_page_range(target_ulong start, target_ulong end)
728{
bellarddc5d0b32004-06-22 18:43:30 +0000729 /* XXX: cannot enable it yet because it yields to MMU exception
730 where NIP != read address on PowerPC */
731#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000732 target_ulong phys_addr;
733 phys_addr = get_phys_addr_code(env, start);
734 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000735#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000736}
737
bellard1a18c712003-10-30 01:07:51 +0000738#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000739
bellard6dbad632003-03-16 18:05:05 +0000740void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
741{
742 CPUX86State *saved_env;
743
744 saved_env = env;
745 env = s;
bellarda412ac52003-07-26 18:01:40 +0000746 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000747 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000748 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000749 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000750 } else {
bellard5d975592008-05-12 22:05:33 +0000751 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000752 }
bellard6dbad632003-03-16 18:05:05 +0000753 env = saved_env;
754}
bellard9de5e442003-03-23 16:49:39 +0000755
bellard6f12a2a2007-11-11 22:16:56 +0000756void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000757{
758 CPUX86State *saved_env;
759
760 saved_env = env;
761 env = s;
ths3b46e622007-09-17 08:09:54 +0000762
bellard6f12a2a2007-11-11 22:16:56 +0000763 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000764
765 env = saved_env;
766}
767
bellard6f12a2a2007-11-11 22:16:56 +0000768void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000769{
770 CPUX86State *saved_env;
771
772 saved_env = env;
773 env = s;
ths3b46e622007-09-17 08:09:54 +0000774
bellard6f12a2a2007-11-11 22:16:56 +0000775 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000776
777 env = saved_env;
778}
779
bellarde4533c72003-06-15 19:51:39 +0000780#endif /* TARGET_I386 */
781
bellard67b915a2004-03-31 23:37:16 +0000782#if !defined(CONFIG_SOFTMMU)
783
bellard3fb2ded2003-06-24 13:22:59 +0000784#if defined(TARGET_I386)
785
bellardb56dad12003-05-08 15:38:04 +0000786/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000787 the effective address of the memory exception. 'is_write' is 1 if a
788 write caused the exception and otherwise 0'. 'old_set' is the
789 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000790static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000791 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000792 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000793{
bellarda513fe12003-05-27 23:29:48 +0000794 TranslationBlock *tb;
795 int ret;
bellard68a79312003-06-30 13:12:32 +0000796
bellard83479e72003-06-25 16:12:37 +0000797 if (cpu_single_env)
798 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000799#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000800 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000801 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000802#endif
bellard25eb4482003-05-14 21:50:54 +0000803 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000804 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000805 return 1;
806 }
bellardfbf9eeb2004-04-25 21:21:33 +0000807
bellard3fb2ded2003-06-24 13:22:59 +0000808 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000809 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000810 if (ret < 0)
811 return 0; /* not an MMU fault */
812 if (ret == 0)
813 return 1; /* the MMU fault was handled without causing real CPU fault */
814 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000815 tb = tb_find_pc(pc);
816 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000817 /* the PC is inside the translated code. It means that we have
818 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000819 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000820 }
bellard4cbf74b2003-08-10 21:48:43 +0000821 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000822#if 0
ths5fafdf22007-09-16 21:08:06 +0000823 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000824 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000825#endif
bellard4cbf74b2003-08-10 21:48:43 +0000826 /* we restore the process signal mask as the sigreturn should
827 do it (XXX: use sigsetjmp) */
828 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000829 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000830 } else {
831 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000832 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000833 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000834 }
bellard3fb2ded2003-06-24 13:22:59 +0000835 /* never comes here */
836 return 1;
837}
838
bellarde4533c72003-06-15 19:51:39 +0000839#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000840static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000841 int is_write, sigset_t *old_set,
842 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000843{
bellard68016c62005-02-07 23:12:27 +0000844 TranslationBlock *tb;
845 int ret;
846
847 if (cpu_single_env)
848 env = cpu_single_env; /* XXX: find a correct solution for multithread */
849#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000850 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000851 pc, address, is_write, *(unsigned long *)old_set);
852#endif
bellard9f0777e2005-02-02 20:42:01 +0000853 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000854 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000855 return 1;
856 }
bellard68016c62005-02-07 23:12:27 +0000857 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000858 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000859 if (ret < 0)
860 return 0; /* not an MMU fault */
861 if (ret == 0)
862 return 1; /* the MMU fault was handled without causing real CPU fault */
863 /* now we have a real cpu fault */
864 tb = tb_find_pc(pc);
865 if (tb) {
866 /* the PC is inside the translated code. It means that we have
867 a virtual CPU fault */
868 cpu_restore_state(tb, env, pc, puc);
869 }
870 /* we restore the process signal mask as the sigreturn should
871 do it (XXX: use sigsetjmp) */
872 sigprocmask(SIG_SETMASK, old_set, NULL);
873 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000874 /* never comes here */
875 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000876}
bellard93ac68b2003-09-30 20:57:29 +0000877#elif defined(TARGET_SPARC)
878static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000879 int is_write, sigset_t *old_set,
880 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000881{
bellard68016c62005-02-07 23:12:27 +0000882 TranslationBlock *tb;
883 int ret;
884
885 if (cpu_single_env)
886 env = cpu_single_env; /* XXX: find a correct solution for multithread */
887#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000888 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000889 pc, address, is_write, *(unsigned long *)old_set);
890#endif
bellardb453b702004-01-04 15:45:21 +0000891 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000892 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000893 return 1;
894 }
bellard68016c62005-02-07 23:12:27 +0000895 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000896 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000897 if (ret < 0)
898 return 0; /* not an MMU fault */
899 if (ret == 0)
900 return 1; /* the MMU fault was handled without causing real CPU fault */
901 /* now we have a real cpu fault */
902 tb = tb_find_pc(pc);
903 if (tb) {
904 /* the PC is inside the translated code. It means that we have
905 a virtual CPU fault */
906 cpu_restore_state(tb, env, pc, puc);
907 }
908 /* we restore the process signal mask as the sigreturn should
909 do it (XXX: use sigsetjmp) */
910 sigprocmask(SIG_SETMASK, old_set, NULL);
911 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000912 /* never comes here */
913 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000914}
bellard67867302003-11-23 17:05:30 +0000915#elif defined (TARGET_PPC)
916static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000917 int is_write, sigset_t *old_set,
918 void *puc)
bellard67867302003-11-23 17:05:30 +0000919{
920 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000921 int ret;
ths3b46e622007-09-17 08:09:54 +0000922
bellard67867302003-11-23 17:05:30 +0000923 if (cpu_single_env)
924 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000925#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000926 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000927 pc, address, is_write, *(unsigned long *)old_set);
928#endif
929 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000930 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000931 return 1;
932 }
933
bellardce097762004-01-04 23:53:18 +0000934 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000935 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000936 if (ret < 0)
937 return 0; /* not an MMU fault */
938 if (ret == 0)
939 return 1; /* the MMU fault was handled without causing real CPU fault */
940
bellard67867302003-11-23 17:05:30 +0000941 /* now we have a real cpu fault */
942 tb = tb_find_pc(pc);
943 if (tb) {
944 /* the PC is inside the translated code. It means that we have
945 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000946 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000947 }
bellardce097762004-01-04 23:53:18 +0000948 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000949#if 0
ths5fafdf22007-09-16 21:08:06 +0000950 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000951 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000952#endif
953 /* we restore the process signal mask as the sigreturn should
954 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000955 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000956 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000957 } else {
958 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000959 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000960 }
bellard67867302003-11-23 17:05:30 +0000961 /* never comes here */
962 return 1;
963}
bellard6af0bf92005-07-02 14:58:51 +0000964
pbrooke6e59062006-10-22 00:18:54 +0000965#elif defined(TARGET_M68K)
966static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
967 int is_write, sigset_t *old_set,
968 void *puc)
969{
970 TranslationBlock *tb;
971 int ret;
972
973 if (cpu_single_env)
974 env = cpu_single_env; /* XXX: find a correct solution for multithread */
975#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000976 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000977 pc, address, is_write, *(unsigned long *)old_set);
978#endif
979 /* XXX: locking issue */
980 if (is_write && page_unprotect(address, pc, puc)) {
981 return 1;
982 }
983 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000984 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000985 if (ret < 0)
986 return 0; /* not an MMU fault */
987 if (ret == 0)
988 return 1; /* the MMU fault was handled without causing real CPU fault */
989 /* now we have a real cpu fault */
990 tb = tb_find_pc(pc);
991 if (tb) {
992 /* the PC is inside the translated code. It means that we have
993 a virtual CPU fault */
994 cpu_restore_state(tb, env, pc, puc);
995 }
996 /* we restore the process signal mask as the sigreturn should
997 do it (XXX: use sigsetjmp) */
998 sigprocmask(SIG_SETMASK, old_set, NULL);
999 cpu_loop_exit();
1000 /* never comes here */
1001 return 1;
1002}
1003
bellard6af0bf92005-07-02 14:58:51 +00001004#elif defined (TARGET_MIPS)
1005static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1006 int is_write, sigset_t *old_set,
1007 void *puc)
1008{
1009 TranslationBlock *tb;
1010 int ret;
ths3b46e622007-09-17 08:09:54 +00001011
bellard6af0bf92005-07-02 14:58:51 +00001012 if (cpu_single_env)
1013 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1014#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001015 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001016 pc, address, is_write, *(unsigned long *)old_set);
1017#endif
1018 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001019 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001020 return 1;
1021 }
1022
1023 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001024 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001025 if (ret < 0)
1026 return 0; /* not an MMU fault */
1027 if (ret == 0)
1028 return 1; /* the MMU fault was handled without causing real CPU fault */
1029
1030 /* now we have a real cpu fault */
1031 tb = tb_find_pc(pc);
1032 if (tb) {
1033 /* the PC is inside the translated code. It means that we have
1034 a virtual CPU fault */
1035 cpu_restore_state(tb, env, pc, puc);
1036 }
1037 if (ret == 1) {
1038#if 0
ths5fafdf22007-09-16 21:08:06 +00001039 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001040 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001041#endif
1042 /* we restore the process signal mask as the sigreturn should
1043 do it (XXX: use sigsetjmp) */
1044 sigprocmask(SIG_SETMASK, old_set, NULL);
1045 do_raise_exception_err(env->exception_index, env->error_code);
1046 } else {
1047 /* activate soft MMU for this block */
1048 cpu_resume_from_signal(env, puc);
1049 }
1050 /* never comes here */
1051 return 1;
1052}
1053
bellardfdf9b3e2006-04-27 21:07:38 +00001054#elif defined (TARGET_SH4)
1055static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1056 int is_write, sigset_t *old_set,
1057 void *puc)
1058{
1059 TranslationBlock *tb;
1060 int ret;
ths3b46e622007-09-17 08:09:54 +00001061
bellardfdf9b3e2006-04-27 21:07:38 +00001062 if (cpu_single_env)
1063 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1064#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001065 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001066 pc, address, is_write, *(unsigned long *)old_set);
1067#endif
1068 /* XXX: locking issue */
1069 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1070 return 1;
1071 }
1072
1073 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001074 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001075 if (ret < 0)
1076 return 0; /* not an MMU fault */
1077 if (ret == 0)
1078 return 1; /* the MMU fault was handled without causing real CPU fault */
1079
1080 /* now we have a real cpu fault */
1081 tb = tb_find_pc(pc);
1082 if (tb) {
1083 /* the PC is inside the translated code. It means that we have
1084 a virtual CPU fault */
1085 cpu_restore_state(tb, env, pc, puc);
1086 }
bellardfdf9b3e2006-04-27 21:07:38 +00001087#if 0
ths5fafdf22007-09-16 21:08:06 +00001088 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001089 env->nip, env->error_code, tb);
1090#endif
1091 /* we restore the process signal mask as the sigreturn should
1092 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001093 sigprocmask(SIG_SETMASK, old_set, NULL);
1094 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001095 /* never comes here */
1096 return 1;
1097}
j_mayereddf68a2007-04-05 07:22:49 +00001098
1099#elif defined (TARGET_ALPHA)
1100static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1101 int is_write, sigset_t *old_set,
1102 void *puc)
1103{
1104 TranslationBlock *tb;
1105 int ret;
ths3b46e622007-09-17 08:09:54 +00001106
j_mayereddf68a2007-04-05 07:22:49 +00001107 if (cpu_single_env)
1108 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1109#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001110 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001111 pc, address, is_write, *(unsigned long *)old_set);
1112#endif
1113 /* XXX: locking issue */
1114 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1115 return 1;
1116 }
1117
1118 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001119 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001120 if (ret < 0)
1121 return 0; /* not an MMU fault */
1122 if (ret == 0)
1123 return 1; /* the MMU fault was handled without causing real CPU fault */
1124
1125 /* now we have a real cpu fault */
1126 tb = tb_find_pc(pc);
1127 if (tb) {
1128 /* the PC is inside the translated code. It means that we have
1129 a virtual CPU fault */
1130 cpu_restore_state(tb, env, pc, puc);
1131 }
1132#if 0
ths5fafdf22007-09-16 21:08:06 +00001133 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001134 env->nip, env->error_code, tb);
1135#endif
1136 /* we restore the process signal mask as the sigreturn should
1137 do it (XXX: use sigsetjmp) */
1138 sigprocmask(SIG_SETMASK, old_set, NULL);
1139 cpu_loop_exit();
1140 /* never comes here */
1141 return 1;
1142}
thsf1ccf902007-10-08 13:16:14 +00001143#elif defined (TARGET_CRIS)
1144static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1145 int is_write, sigset_t *old_set,
1146 void *puc)
1147{
1148 TranslationBlock *tb;
1149 int ret;
1150
1151 if (cpu_single_env)
1152 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1153#if defined(DEBUG_SIGNAL)
1154 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1155 pc, address, is_write, *(unsigned long *)old_set);
1156#endif
1157 /* XXX: locking issue */
1158 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1159 return 1;
1160 }
1161
1162 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001163 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001164 if (ret < 0)
1165 return 0; /* not an MMU fault */
1166 if (ret == 0)
1167 return 1; /* the MMU fault was handled without causing real CPU fault */
1168
1169 /* now we have a real cpu fault */
1170 tb = tb_find_pc(pc);
1171 if (tb) {
1172 /* the PC is inside the translated code. It means that we have
1173 a virtual CPU fault */
1174 cpu_restore_state(tb, env, pc, puc);
1175 }
thsf1ccf902007-10-08 13:16:14 +00001176 /* we restore the process signal mask as the sigreturn should
1177 do it (XXX: use sigsetjmp) */
1178 sigprocmask(SIG_SETMASK, old_set, NULL);
1179 cpu_loop_exit();
1180 /* never comes here */
1181 return 1;
1182}
1183
bellarde4533c72003-06-15 19:51:39 +00001184#else
1185#error unsupported target CPU
1186#endif
bellard9de5e442003-03-23 16:49:39 +00001187
bellard2b413142003-05-14 23:01:10 +00001188#if defined(__i386__)
1189
bellardd8ecc0b2007-02-05 21:41:46 +00001190#if defined(__APPLE__)
1191# include <sys/ucontext.h>
1192
1193# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1194# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1195# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1196#else
1197# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1198# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1199# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1200#endif
1201
ths5fafdf22007-09-16 21:08:06 +00001202int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001203 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001204{
ths5a7b5422007-01-31 12:16:51 +00001205 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001206 struct ucontext *uc = puc;
1207 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001208 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001209
bellardd691f662003-03-24 21:58:34 +00001210#ifndef REG_EIP
1211/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001212#define REG_EIP EIP
1213#define REG_ERR ERR
1214#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001215#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001216 pc = EIP_sig(uc);
1217 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001218 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1219 trapno == 0xe ?
1220 (ERROR_sig(uc) >> 1) & 1 : 0,
1221 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001222}
1223
bellardbc51c5c2004-03-17 23:46:04 +00001224#elif defined(__x86_64__)
1225
ths5a7b5422007-01-31 12:16:51 +00001226int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001227 void *puc)
1228{
ths5a7b5422007-01-31 12:16:51 +00001229 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001230 struct ucontext *uc = puc;
1231 unsigned long pc;
1232
1233 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001234 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1235 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001236 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1237 &uc->uc_sigmask, puc);
1238}
1239
bellard83fb7ad2004-07-05 21:25:26 +00001240#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001241
bellard83fb7ad2004-07-05 21:25:26 +00001242/***********************************************************************
1243 * signal context platform-specific definitions
1244 * From Wine
1245 */
1246#ifdef linux
1247/* All Registers access - only for local access */
1248# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1249/* Gpr Registers access */
1250# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1251# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1252# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1253# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1254# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1255# define LR_sig(context) REG_sig(link, context) /* Link register */
1256# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1257/* Float Registers access */
1258# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1259# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1260/* Exception Registers access */
1261# define DAR_sig(context) REG_sig(dar, context)
1262# define DSISR_sig(context) REG_sig(dsisr, context)
1263# define TRAP_sig(context) REG_sig(trap, context)
1264#endif /* linux */
1265
1266#ifdef __APPLE__
1267# include <sys/ucontext.h>
1268typedef struct ucontext SIGCONTEXT;
1269/* All Registers access - only for local access */
1270# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1271# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1272# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1273# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1274/* Gpr Registers access */
1275# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1276# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1277# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1278# define CTR_sig(context) REG_sig(ctr, context)
1279# define XER_sig(context) REG_sig(xer, context) /* Link register */
1280# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1281# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1282/* Float Registers access */
1283# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1284# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1285/* Exception Registers access */
1286# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1287# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1288# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1289#endif /* __APPLE__ */
1290
ths5fafdf22007-09-16 21:08:06 +00001291int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001292 void *puc)
bellard2b413142003-05-14 23:01:10 +00001293{
ths5a7b5422007-01-31 12:16:51 +00001294 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001295 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001296 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001297 int is_write;
1298
bellard83fb7ad2004-07-05 21:25:26 +00001299 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001300 is_write = 0;
1301#if 0
1302 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001303 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001304 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001305#else
bellard83fb7ad2004-07-05 21:25:26 +00001306 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001307 is_write = 1;
1308#endif
ths5fafdf22007-09-16 21:08:06 +00001309 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001310 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001311}
bellard2b413142003-05-14 23:01:10 +00001312
bellard2f87c602003-06-02 20:38:09 +00001313#elif defined(__alpha__)
1314
ths5fafdf22007-09-16 21:08:06 +00001315int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001316 void *puc)
1317{
ths5a7b5422007-01-31 12:16:51 +00001318 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001319 struct ucontext *uc = puc;
1320 uint32_t *pc = uc->uc_mcontext.sc_pc;
1321 uint32_t insn = *pc;
1322 int is_write = 0;
1323
bellard8c6939c2003-06-09 15:28:00 +00001324 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001325 switch (insn >> 26) {
1326 case 0x0d: // stw
1327 case 0x0e: // stb
1328 case 0x0f: // stq_u
1329 case 0x24: // stf
1330 case 0x25: // stg
1331 case 0x26: // sts
1332 case 0x27: // stt
1333 case 0x2c: // stl
1334 case 0x2d: // stq
1335 case 0x2e: // stl_c
1336 case 0x2f: // stq_c
1337 is_write = 1;
1338 }
1339
ths5fafdf22007-09-16 21:08:06 +00001340 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001341 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001342}
bellard8c6939c2003-06-09 15:28:00 +00001343#elif defined(__sparc__)
1344
ths5fafdf22007-09-16 21:08:06 +00001345int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001346 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001347{
ths5a7b5422007-01-31 12:16:51 +00001348 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001349 int is_write;
1350 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001351#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001352 uint32_t *regs = (uint32_t *)(info + 1);
1353 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001354 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001355 unsigned long pc = regs[1];
1356#else
blueswir184778502008-10-26 20:33:16 +00001357#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001358 struct sigcontext *sc = puc;
1359 unsigned long pc = sc->sigc_regs.tpc;
1360 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001361#elif defined(__OpenBSD__)
1362 struct sigcontext *uc = puc;
1363 unsigned long pc = uc->sc_pc;
1364 void *sigmask = (void *)(long)uc->sc_mask;
1365#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001366#endif
1367
bellard8c6939c2003-06-09 15:28:00 +00001368 /* XXX: need kernel patch to get write flag faster */
1369 is_write = 0;
1370 insn = *(uint32_t *)pc;
1371 if ((insn >> 30) == 3) {
1372 switch((insn >> 19) & 0x3f) {
1373 case 0x05: // stb
1374 case 0x06: // sth
1375 case 0x04: // st
1376 case 0x07: // std
1377 case 0x24: // stf
1378 case 0x27: // stdf
1379 case 0x25: // stfsr
1380 is_write = 1;
1381 break;
1382 }
1383 }
ths5fafdf22007-09-16 21:08:06 +00001384 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001385 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001386}
1387
1388#elif defined(__arm__)
1389
ths5fafdf22007-09-16 21:08:06 +00001390int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001391 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001392{
ths5a7b5422007-01-31 12:16:51 +00001393 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001394 struct ucontext *uc = puc;
1395 unsigned long pc;
1396 int is_write;
ths3b46e622007-09-17 08:09:54 +00001397
blueswir148bbf112008-07-08 18:35:02 +00001398#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001399 pc = uc->uc_mcontext.gregs[R15];
1400#else
balrog4eee57f2008-05-06 14:47:19 +00001401 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001402#endif
bellard8c6939c2003-06-09 15:28:00 +00001403 /* XXX: compute is_write */
1404 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001405 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001406 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001407 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001408}
1409
bellard38e584a2003-08-10 22:14:22 +00001410#elif defined(__mc68000)
1411
ths5fafdf22007-09-16 21:08:06 +00001412int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001413 void *puc)
1414{
ths5a7b5422007-01-31 12:16:51 +00001415 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001416 struct ucontext *uc = puc;
1417 unsigned long pc;
1418 int is_write;
ths3b46e622007-09-17 08:09:54 +00001419
bellard38e584a2003-08-10 22:14:22 +00001420 pc = uc->uc_mcontext.gregs[16];
1421 /* XXX: compute is_write */
1422 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001423 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001424 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001425 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001426}
1427
bellardb8076a72005-04-07 22:20:31 +00001428#elif defined(__ia64)
1429
1430#ifndef __ISR_VALID
1431 /* This ought to be in <bits/siginfo.h>... */
1432# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001433#endif
1434
ths5a7b5422007-01-31 12:16:51 +00001435int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001436{
ths5a7b5422007-01-31 12:16:51 +00001437 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001438 struct ucontext *uc = puc;
1439 unsigned long ip;
1440 int is_write = 0;
1441
1442 ip = uc->uc_mcontext.sc_ip;
1443 switch (host_signum) {
1444 case SIGILL:
1445 case SIGFPE:
1446 case SIGSEGV:
1447 case SIGBUS:
1448 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001449 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001450 /* ISR.W (write-access) is bit 33: */
1451 is_write = (info->si_isr >> 33) & 1;
1452 break;
1453
1454 default:
1455 break;
1456 }
1457 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1458 is_write,
1459 &uc->uc_sigmask, puc);
1460}
1461
bellard90cb9492005-07-24 15:11:38 +00001462#elif defined(__s390__)
1463
ths5fafdf22007-09-16 21:08:06 +00001464int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001465 void *puc)
1466{
ths5a7b5422007-01-31 12:16:51 +00001467 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001468 struct ucontext *uc = puc;
1469 unsigned long pc;
1470 int is_write;
ths3b46e622007-09-17 08:09:54 +00001471
bellard90cb9492005-07-24 15:11:38 +00001472 pc = uc->uc_mcontext.psw.addr;
1473 /* XXX: compute is_write */
1474 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001475 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001476 is_write, &uc->uc_sigmask, puc);
1477}
1478
1479#elif defined(__mips__)
1480
ths5fafdf22007-09-16 21:08:06 +00001481int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001482 void *puc)
1483{
ths9617efe2007-05-08 21:05:55 +00001484 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001485 struct ucontext *uc = puc;
1486 greg_t pc = uc->uc_mcontext.pc;
1487 int is_write;
ths3b46e622007-09-17 08:09:54 +00001488
thsc4b89d12007-05-05 19:23:11 +00001489 /* XXX: compute is_write */
1490 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001491 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001492 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001493}
1494
aurel32f54b3f92008-04-12 20:14:54 +00001495#elif defined(__hppa__)
1496
1497int cpu_signal_handler(int host_signum, void *pinfo,
1498 void *puc)
1499{
1500 struct siginfo *info = pinfo;
1501 struct ucontext *uc = puc;
1502 unsigned long pc;
1503 int is_write;
1504
1505 pc = uc->uc_mcontext.sc_iaoq[0];
1506 /* FIXME: compute is_write */
1507 is_write = 0;
1508 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1509 is_write,
1510 &uc->uc_sigmask, puc);
1511}
1512
bellard2b413142003-05-14 23:01:10 +00001513#else
1514
bellard3fb2ded2003-06-24 13:22:59 +00001515#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001516
1517#endif
bellard67b915a2004-03-31 23:37:16 +00001518
1519#endif /* !defined(CONFIG_SOFTMMU) */