blob: 6995112353934df3618f927e009147813200b484 [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
bellard7d132992003-03-06 23:23:54 +00005 *
bellard3ef693a2003-03-23 20:17:16 +00006 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bellard7d132992003-03-06 23:23:54 +000019 */
bellarde4533c72003-06-15 19:51:39 +000020#include "config.h"
bellard7cb69ca2008-05-10 10:55:51 +000021#define CPU_NO_GLOBAL_REGS
bellard93ac68b2003-09-30 20:57:29 +000022#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000023#include "disas.h"
bellard7cb69ca2008-05-10 10:55:51 +000024#include "tcg.h"
aliguori7ba1e612008-11-05 16:04:33 +000025#include "kvm.h"
bellard7d132992003-03-06 23:23:54 +000026
bellardfbf9eeb2004-04-25 21:21:33 +000027#if !defined(CONFIG_SOFTMMU)
28#undef EAX
29#undef ECX
30#undef EDX
31#undef EBX
32#undef ESP
33#undef EBP
34#undef ESI
35#undef EDI
36#undef EIP
37#include <signal.h>
blueswir184778502008-10-26 20:33:16 +000038#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000039#include <sys/ucontext.h>
40#endif
blueswir184778502008-10-26 20:33:16 +000041#endif
bellardfbf9eeb2004-04-25 21:21:33 +000042
blueswir1572a9d42008-05-17 07:38:10 +000043#if defined(__sparc__) && !defined(HOST_SOLARIS)
44// Work around ugly bugs in glibc that mangle global register contents
45#undef env
46#define env cpu_single_env
47#endif
48
bellard36bdbe52003-11-19 22:12:02 +000049int tb_invalidated_flag;
50
bellarddc990652003-03-19 00:00:28 +000051//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000052//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000053
bellarde4533c72003-06-15 19:51:39 +000054void cpu_loop_exit(void)
55{
thsbfed01f2007-06-03 17:44:37 +000056 /* NOTE: the register at this point must be saved by hand because
57 longjmp restore them */
58 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000059 longjmp(env->jmp_env, 1);
60}
thsbfed01f2007-06-03 17:44:37 +000061
bellardfbf9eeb2004-04-25 21:21:33 +000062/* exit the current TB from a signal handler. The host registers are
63 restored in a state compatible with the CPU emulator
64 */
ths5fafdf22007-09-16 21:08:06 +000065void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000066{
67#if !defined(CONFIG_SOFTMMU)
blueswir184778502008-10-26 20:33:16 +000068#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000069 struct ucontext *uc = puc;
blueswir184778502008-10-26 20:33:16 +000070#elif defined(__OpenBSD__)
71 struct sigcontext *uc = puc;
72#endif
bellardfbf9eeb2004-04-25 21:21:33 +000073#endif
74
75 env = env1;
76
77 /* XXX: restore cpu registers saved in host registers */
78
79#if !defined(CONFIG_SOFTMMU)
80 if (puc) {
81 /* XXX: use siglongjmp ? */
blueswir184778502008-10-26 20:33:16 +000082#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000083 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
blueswir184778502008-10-26 20:33:16 +000084#elif defined(__OpenBSD__)
85 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
86#endif
bellardfbf9eeb2004-04-25 21:21:33 +000087 }
88#endif
89 longjmp(env->jmp_env, 1);
90}
91
pbrook2e70f6e2008-06-29 01:03:05 +000092/* Execute the code without caching the generated code. An interpreter
93 could be used if available. */
94static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
95{
96 unsigned long next_tb;
97 TranslationBlock *tb;
98
99 /* Should never happen.
100 We only end up here when an existing TB is too long. */
101 if (max_cycles > CF_COUNT_MASK)
102 max_cycles = CF_COUNT_MASK;
103
104 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
105 max_cycles);
106 env->current_tb = tb;
107 /* execute the generated code */
108 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
109
110 if ((next_tb & 3) == 2) {
111 /* Restore PC. This may happen if async event occurs before
112 the TB starts executing. */
113 CPU_PC_FROM_TB(env, tb);
114 }
115 tb_phys_invalidate(tb, -1);
116 tb_free(tb);
117}
118
bellard8a40a182005-11-20 10:35:40 +0000119static TranslationBlock *tb_find_slow(target_ulong pc,
120 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000121 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000122{
123 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +0000124 unsigned int h;
125 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
ths3b46e622007-09-17 08:09:54 +0000126
bellard8a40a182005-11-20 10:35:40 +0000127 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000128
bellard8a40a182005-11-20 10:35:40 +0000129 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000130
bellard8a40a182005-11-20 10:35:40 +0000131 /* find translated block using physical mappings */
132 phys_pc = get_phys_addr_code(env, pc);
133 phys_page1 = phys_pc & TARGET_PAGE_MASK;
134 phys_page2 = -1;
135 h = tb_phys_hash_func(phys_pc);
136 ptb1 = &tb_phys_hash[h];
137 for(;;) {
138 tb = *ptb1;
139 if (!tb)
140 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000141 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000142 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000143 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000144 tb->flags == flags) {
145 /* check next page if needed */
146 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000147 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000148 TARGET_PAGE_SIZE;
149 phys_page2 = get_phys_addr_code(env, virt_page2);
150 if (tb->page_addr[1] == phys_page2)
151 goto found;
152 } else {
153 goto found;
154 }
155 }
156 ptb1 = &tb->phys_hash_next;
157 }
158 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000159 /* if no translated code available, then translate it now */
160 tb = tb_gen_code(env, pc, cs_base, flags, 0);
ths3b46e622007-09-17 08:09:54 +0000161
bellard8a40a182005-11-20 10:35:40 +0000162 found:
bellard8a40a182005-11-20 10:35:40 +0000163 /* we add the TB in the virtual pc hash table */
164 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
bellard8a40a182005-11-20 10:35:40 +0000165 return tb;
166}
167
168static inline TranslationBlock *tb_find_fast(void)
169{
170 TranslationBlock *tb;
171 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000172 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000173
174 /* we record a subset of the CPU state. It will
175 always be the same before a given translated block
176 is executed. */
177#if defined(TARGET_I386)
178 flags = env->hflags;
179 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
180 cs_base = env->segs[R_CS].base;
181 pc = cs_base + env->eip;
182#elif defined(TARGET_ARM)
183 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000184 | (env->vfp.vec_stride << 4);
185 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
186 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000187 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
188 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000189 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000190 cs_base = 0;
191 pc = env->regs[15];
192#elif defined(TARGET_SPARC)
193#ifdef TARGET_SPARC64
blueswir12cade6a2008-07-17 12:53:05 +0000194 // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
195 flags = ((env->pstate & PS_AM) << 2)
196 | (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
bellarda80dde02006-06-26 19:53:29 +0000197 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000198#else
blueswir16d5f2372007-11-07 17:03:37 +0000199 // FPU enable . Supervisor
200 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000201#endif
202 cs_base = env->npc;
203 pc = env->pc;
204#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000205 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000206 cs_base = 0;
207 pc = env->nip;
208#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000209 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000210 cs_base = 0;
thsb5dc7732008-06-27 10:02:35 +0000211 pc = env->active_tc.PC;
pbrooke6e59062006-10-22 00:18:54 +0000212#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000213 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
214 | (env->sr & SR_S) /* Bit 13 */
215 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000216 cs_base = 0;
217 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000218#elif defined(TARGET_SH4)
aurel32fe255912008-09-15 08:49:15 +0000219 flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
220 | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */
221 | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */
222 | (env->sr & (SR_MD | SR_RB)); /* Bits 29-30 */
ths823029f2007-12-02 06:10:04 +0000223 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000224 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000225#elif defined(TARGET_ALPHA)
226 flags = env->ps;
227 cs_base = 0;
228 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000229#elif defined(TARGET_CRIS)
edgar_igla1aebcb2008-10-07 22:48:41 +0000230 flags = env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG | X_FLAG);
edgar_iglcf1d97f2008-05-13 10:59:14 +0000231 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000232 cs_base = 0;
233 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000234#else
235#error unsupported CPU
236#endif
bellardbce61842008-02-01 22:18:51 +0000237 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000238 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
239 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000240 tb = tb_find_slow(pc, cs_base, flags);
241 }
242 return tb;
243}
244
bellard7d132992003-03-06 23:23:54 +0000245/* main execution loop */
246
bellarde4533c72003-06-15 19:51:39 +0000247int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000248{
pbrook1057eaa2007-02-04 13:37:44 +0000249#define DECLARE_HOST_REGS 1
250#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000251 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000252 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000253 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000254 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000255
thsbfed01f2007-06-03 17:44:37 +0000256 if (cpu_halted(env1) == EXCP_HALTED)
257 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000258
ths5fafdf22007-09-16 21:08:06 +0000259 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000260
bellard7d132992003-03-06 23:23:54 +0000261 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000262#define SAVE_HOST_REGS 1
263#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000264 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000265
bellard0d1a29f2004-10-12 22:01:28 +0000266 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000267#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000268 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000269 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
270 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000271 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000272 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000273#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000274#elif defined(TARGET_M68K)
275 env->cc_op = CC_OP_FLAGS;
276 env->cc_dest = env->sr & 0xf;
277 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000278#elif defined(TARGET_ALPHA)
279#elif defined(TARGET_ARM)
280#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000281#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000282#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000283#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000284 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000285#else
286#error unsupported target CPU
287#endif
bellard3fb2ded2003-06-24 13:22:59 +0000288 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000289
bellard7d132992003-03-06 23:23:54 +0000290 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000291 for(;;) {
292 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000293 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000294 /* if an exception is pending, we execute it here */
295 if (env->exception_index >= 0) {
296 if (env->exception_index >= EXCP_INTERRUPT) {
297 /* exit request from the cpu execution loop */
298 ret = env->exception_index;
299 break;
300 } else if (env->user_mode_only) {
301 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000302 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000303 loop */
bellard83479e72003-06-25 16:12:37 +0000304#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000305 do_interrupt_user(env->exception_index,
306 env->exception_is_int,
307 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000308 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000309 /* successfully delivered */
310 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000311#endif
bellard3fb2ded2003-06-24 13:22:59 +0000312 ret = env->exception_index;
313 break;
314 } else {
bellard83479e72003-06-25 16:12:37 +0000315#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000316 /* simulate a real cpu exception. On i386, it can
317 trigger new exceptions, but we do not handle
318 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000319 do_interrupt(env->exception_index,
320 env->exception_is_int,
321 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000322 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000323 /* successfully delivered */
324 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000325#elif defined(TARGET_PPC)
326 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000327#elif defined(TARGET_MIPS)
328 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000329#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000330 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000331#elif defined(TARGET_ARM)
332 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000333#elif defined(TARGET_SH4)
334 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000335#elif defined(TARGET_ALPHA)
336 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000337#elif defined(TARGET_CRIS)
338 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000339#elif defined(TARGET_M68K)
340 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000341#endif
bellard3fb2ded2003-06-24 13:22:59 +0000342 }
343 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000344 }
bellard9df217a2005-02-10 22:05:51 +0000345#ifdef USE_KQEMU
346 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
347 int ret;
348 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
349 ret = kqemu_cpu_exec(env);
350 /* put eflags in CPU temporary format */
351 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
352 DF = 1 - (2 * ((env->eflags >> 10) & 1));
353 CC_OP = CC_OP_EFLAGS;
354 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
355 if (ret == 1) {
356 /* exception */
357 longjmp(env->jmp_env, 1);
358 } else if (ret == 2) {
359 /* softmmu execution needed */
360 } else {
361 if (env->interrupt_request != 0) {
362 /* hardware interrupt will be executed just after */
363 } else {
364 /* otherwise, we restart */
365 longjmp(env->jmp_env, 1);
366 }
367 }
bellard9de5e442003-03-23 16:49:39 +0000368 }
bellard9df217a2005-02-10 22:05:51 +0000369#endif
370
aliguori7ba1e612008-11-05 16:04:33 +0000371 if (kvm_enabled()) {
372 int ret;
373 ret = kvm_cpu_exec(env);
374 if ((env->interrupt_request & CPU_INTERRUPT_EXIT)) {
375 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
376 env->exception_index = EXCP_INTERRUPT;
377 cpu_loop_exit();
378 } else if (env->halted) {
379 cpu_loop_exit();
380 } else
381 longjmp(env->jmp_env, 1);
382 }
383
blueswir1b5fc09a2008-05-04 06:38:18 +0000384 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000385 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000386 interrupt_request = env->interrupt_request;
ths551bd272008-07-03 17:57:36 +0000387 if (unlikely(interrupt_request) &&
bellarddb620f42008-06-04 17:02:19 +0000388 likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
pbrook6658ffb2007-03-16 23:58:11 +0000389 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
390 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
391 env->exception_index = EXCP_DEBUG;
392 cpu_loop_exit();
393 }
balroga90b7312007-05-01 01:28:01 +0000394#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000395 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000396 if (interrupt_request & CPU_INTERRUPT_HALT) {
397 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
398 env->halted = 1;
399 env->exception_index = EXCP_HLT;
400 cpu_loop_exit();
401 }
402#endif
bellard68a79312003-06-30 13:12:32 +0000403#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000404 if (env->hflags2 & HF2_GIF_MASK) {
405 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
406 !(env->hflags & HF_SMM_MASK)) {
407 svm_check_intercept(SVM_EXIT_SMI);
408 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
409 do_smm_enter();
410 next_tb = 0;
411 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
412 !(env->hflags2 & HF2_NMI_MASK)) {
413 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
414 env->hflags2 |= HF2_NMI_MASK;
415 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
416 next_tb = 0;
417 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
418 (((env->hflags2 & HF2_VINTR_MASK) &&
419 (env->hflags2 & HF2_HIF_MASK)) ||
420 (!(env->hflags2 & HF2_VINTR_MASK) &&
421 (env->eflags & IF_MASK &&
422 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
423 int intno;
424 svm_check_intercept(SVM_EXIT_INTR);
425 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
426 intno = cpu_get_pic_interrupt(env);
427 if (loglevel & CPU_LOG_TB_IN_ASM) {
428 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
429 }
430 do_interrupt(intno, 0, 0, 0, 1);
431 /* ensure that no TB jump will be modified as
432 the program flow was changed */
433 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000434#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000435 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
436 (env->eflags & IF_MASK) &&
437 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
438 int intno;
439 /* FIXME: this should respect TPR */
440 svm_check_intercept(SVM_EXIT_VINTR);
441 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
442 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
443 if (loglevel & CPU_LOG_TB_IN_ASM)
444 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
445 do_interrupt(intno, 0, 0, 0, 1);
446 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000447#endif
bellarddb620f42008-06-04 17:02:19 +0000448 }
bellard68a79312003-06-30 13:12:32 +0000449 }
bellardce097762004-01-04 23:53:18 +0000450#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000451#if 0
452 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
453 cpu_ppc_reset(env);
454 }
455#endif
j_mayer47103572007-03-30 09:38:04 +0000456 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000457 ppc_hw_interrupt(env);
458 if (env->pending_interrupts == 0)
459 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000460 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000461 }
bellard6af0bf92005-07-02 14:58:51 +0000462#elif defined(TARGET_MIPS)
463 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000464 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000465 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000466 !(env->CP0_Status & (1 << CP0St_EXL)) &&
467 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000468 !(env->hflags & MIPS_HFLAG_DM)) {
469 /* Raise it */
470 env->exception_index = EXCP_EXT_INTERRUPT;
471 env->error_code = 0;
472 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000473 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000474 }
bellarde95c8d52004-09-30 22:22:08 +0000475#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000476 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
477 (env->psret != 0)) {
478 int pil = env->interrupt_index & 15;
479 int type = env->interrupt_index & 0xf0;
480
481 if (((type == TT_EXTINT) &&
482 (pil == 15 || pil > env->psrpil)) ||
483 type != TT_EXTINT) {
484 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000485 env->exception_index = env->interrupt_index;
486 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000487 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000488#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
489 cpu_check_irqs(env);
490#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000491 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000492 }
bellarde95c8d52004-09-30 22:22:08 +0000493 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
494 //do_interrupt(0, 0, 0, 0, 0);
495 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000496 }
bellardb5ff1b32005-11-26 10:38:39 +0000497#elif defined(TARGET_ARM)
498 if (interrupt_request & CPU_INTERRUPT_FIQ
499 && !(env->uncached_cpsr & CPSR_F)) {
500 env->exception_index = EXCP_FIQ;
501 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000502 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000503 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000504 /* ARMv7-M interrupt return works by loading a magic value
505 into the PC. On real hardware the load causes the
506 return to occur. The qemu implementation performs the
507 jump normally, then does the exception return when the
508 CPU tries to execute code at the magic address.
509 This will cause the magic PC value to be pushed to
510 the stack if an interrupt occured at the wrong time.
511 We avoid this by disabling interrupts when
512 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000513 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000514 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
515 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000516 env->exception_index = EXCP_IRQ;
517 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000518 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000519 }
bellardfdf9b3e2006-04-27 21:07:38 +0000520#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000521 if (interrupt_request & CPU_INTERRUPT_HARD) {
522 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000523 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000524 }
j_mayereddf68a2007-04-05 07:22:49 +0000525#elif defined(TARGET_ALPHA)
526 if (interrupt_request & CPU_INTERRUPT_HARD) {
527 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000528 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000529 }
thsf1ccf902007-10-08 13:16:14 +0000530#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000531 if (interrupt_request & CPU_INTERRUPT_HARD
532 && (env->pregs[PR_CCS] & I_FLAG)) {
533 env->exception_index = EXCP_IRQ;
534 do_interrupt(env);
535 next_tb = 0;
536 }
537 if (interrupt_request & CPU_INTERRUPT_NMI
538 && (env->pregs[PR_CCS] & M_FLAG)) {
539 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000540 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000541 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000542 }
pbrook06338792007-05-23 19:58:11 +0000543#elif defined(TARGET_M68K)
544 if (interrupt_request & CPU_INTERRUPT_HARD
545 && ((env->sr & SR_I) >> SR_I_SHIFT)
546 < env->pending_level) {
547 /* Real hardware gets the interrupt vector via an
548 IACK cycle at this point. Current emulated
549 hardware doesn't rely on this, so we
550 provide/save the vector when the interrupt is
551 first signalled. */
552 env->exception_index = env->pending_vector;
553 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000554 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000555 }
bellard68a79312003-06-30 13:12:32 +0000556#endif
bellard9d050952006-05-22 22:03:52 +0000557 /* Don't use the cached interupt_request value,
558 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000559 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000560 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
561 /* ensure that no TB jump will be modified as
562 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000563 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000564 }
bellard68a79312003-06-30 13:12:32 +0000565 if (interrupt_request & CPU_INTERRUPT_EXIT) {
566 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
567 env->exception_index = EXCP_INTERRUPT;
568 cpu_loop_exit();
569 }
bellard3fb2ded2003-06-24 13:22:59 +0000570 }
571#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000572 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000573 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000574 regs_to_env();
575#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000576 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000577 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000578 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000579#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000580 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000581#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000582 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000583#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000584 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000585#elif defined(TARGET_M68K)
586 cpu_m68k_flush_flags(env, env->cc_op);
587 env->cc_op = CC_OP_FLAGS;
588 env->sr = (env->sr & 0xffe0)
589 | env->cc_dest | (env->cc_x << 4);
590 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000591#elif defined(TARGET_MIPS)
592 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000593#elif defined(TARGET_SH4)
594 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000595#elif defined(TARGET_ALPHA)
596 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000597#elif defined(TARGET_CRIS)
598 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000599#else
ths5fafdf22007-09-16 21:08:06 +0000600#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000601#endif
bellard3fb2ded2003-06-24 13:22:59 +0000602 }
bellard7d132992003-03-06 23:23:54 +0000603#endif
pbrookd5975362008-06-07 20:50:51 +0000604 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000605 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000606 /* Note: we do it here to avoid a gcc bug on Mac OS X when
607 doing it in tb_find_slow */
608 if (tb_invalidated_flag) {
609 /* as some TB could have been invalidated because
610 of memory exceptions while generating the code, we
611 must recompute the hash index here */
612 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000613 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000614 }
bellard9d27abd2003-05-10 13:13:54 +0000615#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000616 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000617 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
618 (long)tb->tc_ptr, tb->pc,
619 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000620 }
bellard9d27abd2003-05-10 13:13:54 +0000621#endif
bellard8a40a182005-11-20 10:35:40 +0000622 /* see if we can patch the calling TB. When the TB
623 spans two pages, we cannot safely do a direct
624 jump. */
bellardc27004e2005-01-03 23:35:10 +0000625 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000626 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000627#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000628 (env->kqemu_enabled != 2) &&
629#endif
bellardec6338b2007-11-08 14:25:03 +0000630 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000631 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000632 }
bellardc27004e2005-01-03 23:35:10 +0000633 }
pbrookd5975362008-06-07 20:50:51 +0000634 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000635 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000636
637 /* cpu_interrupt might be called while translating the
638 TB, but before it is linked into a potentially
639 infinite loop and becomes env->current_tb. Avoid
640 starting execution if there is a pending interrupt. */
641 if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
642 env->current_tb = NULL;
643
pbrook2e70f6e2008-06-29 01:03:05 +0000644 while (env->current_tb) {
645 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000646 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000647#if defined(__sparc__) && !defined(HOST_SOLARIS)
648#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000649 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000650#define env cpu_single_env
651#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000652 next_tb = tcg_qemu_tb_exec(tc_ptr);
653 env->current_tb = NULL;
654 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000655 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000656 int insns_left;
657 tb = (TranslationBlock *)(long)(next_tb & ~3);
658 /* Restore PC. */
659 CPU_PC_FROM_TB(env, tb);
660 insns_left = env->icount_decr.u32;
661 if (env->icount_extra && insns_left >= 0) {
662 /* Refill decrementer and continue execution. */
663 env->icount_extra += insns_left;
664 if (env->icount_extra > 0xffff) {
665 insns_left = 0xffff;
666 } else {
667 insns_left = env->icount_extra;
668 }
669 env->icount_extra -= insns_left;
670 env->icount_decr.u16.low = insns_left;
671 } else {
672 if (insns_left > 0) {
673 /* Execute remaining instructions. */
674 cpu_exec_nocache(insns_left, tb);
675 }
676 env->exception_index = EXCP_INTERRUPT;
677 next_tb = 0;
678 cpu_loop_exit();
679 }
680 }
681 }
bellard4cbf74b2003-08-10 21:48:43 +0000682 /* reset soft MMU for next block (it can currently
683 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000684#if defined(USE_KQEMU)
685#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
686 if (kqemu_is_ok(env) &&
687 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
688 cpu_loop_exit();
689 }
690#endif
ths50a518e2007-06-03 18:52:15 +0000691 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000692 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000693 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000694 }
bellard3fb2ded2003-06-24 13:22:59 +0000695 } /* for(;;) */
696
bellard7d132992003-03-06 23:23:54 +0000697
bellarde4533c72003-06-15 19:51:39 +0000698#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000699 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000700 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000701#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000702 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000703#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000704#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000705#elif defined(TARGET_M68K)
706 cpu_m68k_flush_flags(env, env->cc_op);
707 env->cc_op = CC_OP_FLAGS;
708 env->sr = (env->sr & 0xffe0)
709 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000710#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000711#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000712#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000713#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000714 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000715#else
716#error unsupported target CPU
717#endif
pbrook1057eaa2007-02-04 13:37:44 +0000718
719 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000720#include "hostregs_helper.h"
721
bellard6a00d602005-11-21 23:25:50 +0000722 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000723 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000724 return ret;
725}
bellard6dbad632003-03-16 18:05:05 +0000726
bellardfbf9eeb2004-04-25 21:21:33 +0000727/* must only be called from the generated code as an exception can be
728 generated */
729void tb_invalidate_page_range(target_ulong start, target_ulong end)
730{
bellarddc5d0b32004-06-22 18:43:30 +0000731 /* XXX: cannot enable it yet because it yields to MMU exception
732 where NIP != read address on PowerPC */
733#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000734 target_ulong phys_addr;
735 phys_addr = get_phys_addr_code(env, start);
736 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000737#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000738}
739
bellard1a18c712003-10-30 01:07:51 +0000740#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000741
bellard6dbad632003-03-16 18:05:05 +0000742void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
743{
744 CPUX86State *saved_env;
745
746 saved_env = env;
747 env = s;
bellarda412ac52003-07-26 18:01:40 +0000748 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000749 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000750 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000751 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000752 } else {
bellard5d975592008-05-12 22:05:33 +0000753 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000754 }
bellard6dbad632003-03-16 18:05:05 +0000755 env = saved_env;
756}
bellard9de5e442003-03-23 16:49:39 +0000757
bellard6f12a2a2007-11-11 22:16:56 +0000758void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000759{
760 CPUX86State *saved_env;
761
762 saved_env = env;
763 env = s;
ths3b46e622007-09-17 08:09:54 +0000764
bellard6f12a2a2007-11-11 22:16:56 +0000765 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000766
767 env = saved_env;
768}
769
bellard6f12a2a2007-11-11 22:16:56 +0000770void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000771{
772 CPUX86State *saved_env;
773
774 saved_env = env;
775 env = s;
ths3b46e622007-09-17 08:09:54 +0000776
bellard6f12a2a2007-11-11 22:16:56 +0000777 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000778
779 env = saved_env;
780}
781
bellarde4533c72003-06-15 19:51:39 +0000782#endif /* TARGET_I386 */
783
bellard67b915a2004-03-31 23:37:16 +0000784#if !defined(CONFIG_SOFTMMU)
785
bellard3fb2ded2003-06-24 13:22:59 +0000786#if defined(TARGET_I386)
787
bellardb56dad12003-05-08 15:38:04 +0000788/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000789 the effective address of the memory exception. 'is_write' is 1 if a
790 write caused the exception and otherwise 0'. 'old_set' is the
791 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000792static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000793 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000794 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000795{
bellarda513fe12003-05-27 23:29:48 +0000796 TranslationBlock *tb;
797 int ret;
bellard68a79312003-06-30 13:12:32 +0000798
bellard83479e72003-06-25 16:12:37 +0000799 if (cpu_single_env)
800 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000801#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000802 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000803 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000804#endif
bellard25eb4482003-05-14 21:50:54 +0000805 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000806 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000807 return 1;
808 }
bellardfbf9eeb2004-04-25 21:21:33 +0000809
bellard3fb2ded2003-06-24 13:22:59 +0000810 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000811 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000812 if (ret < 0)
813 return 0; /* not an MMU fault */
814 if (ret == 0)
815 return 1; /* the MMU fault was handled without causing real CPU fault */
816 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000817 tb = tb_find_pc(pc);
818 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000819 /* the PC is inside the translated code. It means that we have
820 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000821 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000822 }
bellard4cbf74b2003-08-10 21:48:43 +0000823 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000824#if 0
ths5fafdf22007-09-16 21:08:06 +0000825 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000826 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000827#endif
bellard4cbf74b2003-08-10 21:48:43 +0000828 /* we restore the process signal mask as the sigreturn should
829 do it (XXX: use sigsetjmp) */
830 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000831 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000832 } else {
833 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000834 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000835 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000836 }
bellard3fb2ded2003-06-24 13:22:59 +0000837 /* never comes here */
838 return 1;
839}
840
bellarde4533c72003-06-15 19:51:39 +0000841#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000842static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000843 int is_write, sigset_t *old_set,
844 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000845{
bellard68016c62005-02-07 23:12:27 +0000846 TranslationBlock *tb;
847 int ret;
848
849 if (cpu_single_env)
850 env = cpu_single_env; /* XXX: find a correct solution for multithread */
851#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000852 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000853 pc, address, is_write, *(unsigned long *)old_set);
854#endif
bellard9f0777e2005-02-02 20:42:01 +0000855 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000856 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000857 return 1;
858 }
bellard68016c62005-02-07 23:12:27 +0000859 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000860 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000861 if (ret < 0)
862 return 0; /* not an MMU fault */
863 if (ret == 0)
864 return 1; /* the MMU fault was handled without causing real CPU fault */
865 /* now we have a real cpu fault */
866 tb = tb_find_pc(pc);
867 if (tb) {
868 /* the PC is inside the translated code. It means that we have
869 a virtual CPU fault */
870 cpu_restore_state(tb, env, pc, puc);
871 }
872 /* we restore the process signal mask as the sigreturn should
873 do it (XXX: use sigsetjmp) */
874 sigprocmask(SIG_SETMASK, old_set, NULL);
875 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000876 /* never comes here */
877 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000878}
bellard93ac68b2003-09-30 20:57:29 +0000879#elif defined(TARGET_SPARC)
880static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000881 int is_write, sigset_t *old_set,
882 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000883{
bellard68016c62005-02-07 23:12:27 +0000884 TranslationBlock *tb;
885 int ret;
886
887 if (cpu_single_env)
888 env = cpu_single_env; /* XXX: find a correct solution for multithread */
889#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000890 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000891 pc, address, is_write, *(unsigned long *)old_set);
892#endif
bellardb453b702004-01-04 15:45:21 +0000893 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000894 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000895 return 1;
896 }
bellard68016c62005-02-07 23:12:27 +0000897 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000898 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000899 if (ret < 0)
900 return 0; /* not an MMU fault */
901 if (ret == 0)
902 return 1; /* the MMU fault was handled without causing real CPU fault */
903 /* now we have a real cpu fault */
904 tb = tb_find_pc(pc);
905 if (tb) {
906 /* the PC is inside the translated code. It means that we have
907 a virtual CPU fault */
908 cpu_restore_state(tb, env, pc, puc);
909 }
910 /* we restore the process signal mask as the sigreturn should
911 do it (XXX: use sigsetjmp) */
912 sigprocmask(SIG_SETMASK, old_set, NULL);
913 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000914 /* never comes here */
915 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000916}
bellard67867302003-11-23 17:05:30 +0000917#elif defined (TARGET_PPC)
918static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000919 int is_write, sigset_t *old_set,
920 void *puc)
bellard67867302003-11-23 17:05:30 +0000921{
922 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000923 int ret;
ths3b46e622007-09-17 08:09:54 +0000924
bellard67867302003-11-23 17:05:30 +0000925 if (cpu_single_env)
926 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000927#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000928 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000929 pc, address, is_write, *(unsigned long *)old_set);
930#endif
931 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000932 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000933 return 1;
934 }
935
bellardce097762004-01-04 23:53:18 +0000936 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000937 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000938 if (ret < 0)
939 return 0; /* not an MMU fault */
940 if (ret == 0)
941 return 1; /* the MMU fault was handled without causing real CPU fault */
942
bellard67867302003-11-23 17:05:30 +0000943 /* now we have a real cpu fault */
944 tb = tb_find_pc(pc);
945 if (tb) {
946 /* the PC is inside the translated code. It means that we have
947 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000948 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000949 }
bellardce097762004-01-04 23:53:18 +0000950 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000951#if 0
ths5fafdf22007-09-16 21:08:06 +0000952 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000953 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000954#endif
955 /* we restore the process signal mask as the sigreturn should
956 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000957 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000958 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000959 } else {
960 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000961 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000962 }
bellard67867302003-11-23 17:05:30 +0000963 /* never comes here */
964 return 1;
965}
bellard6af0bf92005-07-02 14:58:51 +0000966
pbrooke6e59062006-10-22 00:18:54 +0000967#elif defined(TARGET_M68K)
968static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
969 int is_write, sigset_t *old_set,
970 void *puc)
971{
972 TranslationBlock *tb;
973 int ret;
974
975 if (cpu_single_env)
976 env = cpu_single_env; /* XXX: find a correct solution for multithread */
977#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000978 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000979 pc, address, is_write, *(unsigned long *)old_set);
980#endif
981 /* XXX: locking issue */
982 if (is_write && page_unprotect(address, pc, puc)) {
983 return 1;
984 }
985 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000986 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000987 if (ret < 0)
988 return 0; /* not an MMU fault */
989 if (ret == 0)
990 return 1; /* the MMU fault was handled without causing real CPU fault */
991 /* now we have a real cpu fault */
992 tb = tb_find_pc(pc);
993 if (tb) {
994 /* the PC is inside the translated code. It means that we have
995 a virtual CPU fault */
996 cpu_restore_state(tb, env, pc, puc);
997 }
998 /* we restore the process signal mask as the sigreturn should
999 do it (XXX: use sigsetjmp) */
1000 sigprocmask(SIG_SETMASK, old_set, NULL);
1001 cpu_loop_exit();
1002 /* never comes here */
1003 return 1;
1004}
1005
bellard6af0bf92005-07-02 14:58:51 +00001006#elif defined (TARGET_MIPS)
1007static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1008 int is_write, sigset_t *old_set,
1009 void *puc)
1010{
1011 TranslationBlock *tb;
1012 int ret;
ths3b46e622007-09-17 08:09:54 +00001013
bellard6af0bf92005-07-02 14:58:51 +00001014 if (cpu_single_env)
1015 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1016#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001017 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001018 pc, address, is_write, *(unsigned long *)old_set);
1019#endif
1020 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001021 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001022 return 1;
1023 }
1024
1025 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001026 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001027 if (ret < 0)
1028 return 0; /* not an MMU fault */
1029 if (ret == 0)
1030 return 1; /* the MMU fault was handled without causing real CPU fault */
1031
1032 /* now we have a real cpu fault */
1033 tb = tb_find_pc(pc);
1034 if (tb) {
1035 /* the PC is inside the translated code. It means that we have
1036 a virtual CPU fault */
1037 cpu_restore_state(tb, env, pc, puc);
1038 }
1039 if (ret == 1) {
1040#if 0
ths5fafdf22007-09-16 21:08:06 +00001041 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001042 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001043#endif
1044 /* we restore the process signal mask as the sigreturn should
1045 do it (XXX: use sigsetjmp) */
1046 sigprocmask(SIG_SETMASK, old_set, NULL);
1047 do_raise_exception_err(env->exception_index, env->error_code);
1048 } else {
1049 /* activate soft MMU for this block */
1050 cpu_resume_from_signal(env, puc);
1051 }
1052 /* never comes here */
1053 return 1;
1054}
1055
bellardfdf9b3e2006-04-27 21:07:38 +00001056#elif defined (TARGET_SH4)
1057static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1058 int is_write, sigset_t *old_set,
1059 void *puc)
1060{
1061 TranslationBlock *tb;
1062 int ret;
ths3b46e622007-09-17 08:09:54 +00001063
bellardfdf9b3e2006-04-27 21:07:38 +00001064 if (cpu_single_env)
1065 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1066#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001067 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001068 pc, address, is_write, *(unsigned long *)old_set);
1069#endif
1070 /* XXX: locking issue */
1071 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1072 return 1;
1073 }
1074
1075 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001076 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001077 if (ret < 0)
1078 return 0; /* not an MMU fault */
1079 if (ret == 0)
1080 return 1; /* the MMU fault was handled without causing real CPU fault */
1081
1082 /* now we have a real cpu fault */
1083 tb = tb_find_pc(pc);
1084 if (tb) {
1085 /* the PC is inside the translated code. It means that we have
1086 a virtual CPU fault */
1087 cpu_restore_state(tb, env, pc, puc);
1088 }
bellardfdf9b3e2006-04-27 21:07:38 +00001089#if 0
ths5fafdf22007-09-16 21:08:06 +00001090 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001091 env->nip, env->error_code, tb);
1092#endif
1093 /* we restore the process signal mask as the sigreturn should
1094 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001095 sigprocmask(SIG_SETMASK, old_set, NULL);
1096 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001097 /* never comes here */
1098 return 1;
1099}
j_mayereddf68a2007-04-05 07:22:49 +00001100
1101#elif defined (TARGET_ALPHA)
1102static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1103 int is_write, sigset_t *old_set,
1104 void *puc)
1105{
1106 TranslationBlock *tb;
1107 int ret;
ths3b46e622007-09-17 08:09:54 +00001108
j_mayereddf68a2007-04-05 07:22:49 +00001109 if (cpu_single_env)
1110 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1111#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001112 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001113 pc, address, is_write, *(unsigned long *)old_set);
1114#endif
1115 /* XXX: locking issue */
1116 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1117 return 1;
1118 }
1119
1120 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001121 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001122 if (ret < 0)
1123 return 0; /* not an MMU fault */
1124 if (ret == 0)
1125 return 1; /* the MMU fault was handled without causing real CPU fault */
1126
1127 /* now we have a real cpu fault */
1128 tb = tb_find_pc(pc);
1129 if (tb) {
1130 /* the PC is inside the translated code. It means that we have
1131 a virtual CPU fault */
1132 cpu_restore_state(tb, env, pc, puc);
1133 }
1134#if 0
ths5fafdf22007-09-16 21:08:06 +00001135 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001136 env->nip, env->error_code, tb);
1137#endif
1138 /* we restore the process signal mask as the sigreturn should
1139 do it (XXX: use sigsetjmp) */
1140 sigprocmask(SIG_SETMASK, old_set, NULL);
1141 cpu_loop_exit();
1142 /* never comes here */
1143 return 1;
1144}
thsf1ccf902007-10-08 13:16:14 +00001145#elif defined (TARGET_CRIS)
1146static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1147 int is_write, sigset_t *old_set,
1148 void *puc)
1149{
1150 TranslationBlock *tb;
1151 int ret;
1152
1153 if (cpu_single_env)
1154 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1155#if defined(DEBUG_SIGNAL)
1156 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1157 pc, address, is_write, *(unsigned long *)old_set);
1158#endif
1159 /* XXX: locking issue */
1160 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1161 return 1;
1162 }
1163
1164 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001165 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001166 if (ret < 0)
1167 return 0; /* not an MMU fault */
1168 if (ret == 0)
1169 return 1; /* the MMU fault was handled without causing real CPU fault */
1170
1171 /* now we have a real cpu fault */
1172 tb = tb_find_pc(pc);
1173 if (tb) {
1174 /* the PC is inside the translated code. It means that we have
1175 a virtual CPU fault */
1176 cpu_restore_state(tb, env, pc, puc);
1177 }
thsf1ccf902007-10-08 13:16:14 +00001178 /* we restore the process signal mask as the sigreturn should
1179 do it (XXX: use sigsetjmp) */
1180 sigprocmask(SIG_SETMASK, old_set, NULL);
1181 cpu_loop_exit();
1182 /* never comes here */
1183 return 1;
1184}
1185
bellarde4533c72003-06-15 19:51:39 +00001186#else
1187#error unsupported target CPU
1188#endif
bellard9de5e442003-03-23 16:49:39 +00001189
bellard2b413142003-05-14 23:01:10 +00001190#if defined(__i386__)
1191
bellardd8ecc0b2007-02-05 21:41:46 +00001192#if defined(__APPLE__)
1193# include <sys/ucontext.h>
1194
1195# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1196# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1197# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1198#else
1199# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1200# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1201# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1202#endif
1203
ths5fafdf22007-09-16 21:08:06 +00001204int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001205 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001206{
ths5a7b5422007-01-31 12:16:51 +00001207 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001208 struct ucontext *uc = puc;
1209 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001210 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001211
bellardd691f662003-03-24 21:58:34 +00001212#ifndef REG_EIP
1213/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001214#define REG_EIP EIP
1215#define REG_ERR ERR
1216#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001217#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001218 pc = EIP_sig(uc);
1219 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001220 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1221 trapno == 0xe ?
1222 (ERROR_sig(uc) >> 1) & 1 : 0,
1223 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001224}
1225
bellardbc51c5c2004-03-17 23:46:04 +00001226#elif defined(__x86_64__)
1227
ths5a7b5422007-01-31 12:16:51 +00001228int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001229 void *puc)
1230{
ths5a7b5422007-01-31 12:16:51 +00001231 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001232 struct ucontext *uc = puc;
1233 unsigned long pc;
1234
1235 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001236 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1237 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001238 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1239 &uc->uc_sigmask, puc);
1240}
1241
bellard83fb7ad2004-07-05 21:25:26 +00001242#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001243
bellard83fb7ad2004-07-05 21:25:26 +00001244/***********************************************************************
1245 * signal context platform-specific definitions
1246 * From Wine
1247 */
1248#ifdef linux
1249/* All Registers access - only for local access */
1250# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1251/* Gpr Registers access */
1252# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1253# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1254# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1255# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1256# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1257# define LR_sig(context) REG_sig(link, context) /* Link register */
1258# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1259/* Float Registers access */
1260# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1261# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1262/* Exception Registers access */
1263# define DAR_sig(context) REG_sig(dar, context)
1264# define DSISR_sig(context) REG_sig(dsisr, context)
1265# define TRAP_sig(context) REG_sig(trap, context)
1266#endif /* linux */
1267
1268#ifdef __APPLE__
1269# include <sys/ucontext.h>
1270typedef struct ucontext SIGCONTEXT;
1271/* All Registers access - only for local access */
1272# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1273# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1274# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1275# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1276/* Gpr Registers access */
1277# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1278# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1279# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1280# define CTR_sig(context) REG_sig(ctr, context)
1281# define XER_sig(context) REG_sig(xer, context) /* Link register */
1282# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1283# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1284/* Float Registers access */
1285# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1286# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1287/* Exception Registers access */
1288# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1289# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1290# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1291#endif /* __APPLE__ */
1292
ths5fafdf22007-09-16 21:08:06 +00001293int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001294 void *puc)
bellard2b413142003-05-14 23:01:10 +00001295{
ths5a7b5422007-01-31 12:16:51 +00001296 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001297 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001298 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001299 int is_write;
1300
bellard83fb7ad2004-07-05 21:25:26 +00001301 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001302 is_write = 0;
1303#if 0
1304 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001305 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001306 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001307#else
bellard83fb7ad2004-07-05 21:25:26 +00001308 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001309 is_write = 1;
1310#endif
ths5fafdf22007-09-16 21:08:06 +00001311 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001312 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001313}
bellard2b413142003-05-14 23:01:10 +00001314
bellard2f87c602003-06-02 20:38:09 +00001315#elif defined(__alpha__)
1316
ths5fafdf22007-09-16 21:08:06 +00001317int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001318 void *puc)
1319{
ths5a7b5422007-01-31 12:16:51 +00001320 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001321 struct ucontext *uc = puc;
1322 uint32_t *pc = uc->uc_mcontext.sc_pc;
1323 uint32_t insn = *pc;
1324 int is_write = 0;
1325
bellard8c6939c2003-06-09 15:28:00 +00001326 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001327 switch (insn >> 26) {
1328 case 0x0d: // stw
1329 case 0x0e: // stb
1330 case 0x0f: // stq_u
1331 case 0x24: // stf
1332 case 0x25: // stg
1333 case 0x26: // sts
1334 case 0x27: // stt
1335 case 0x2c: // stl
1336 case 0x2d: // stq
1337 case 0x2e: // stl_c
1338 case 0x2f: // stq_c
1339 is_write = 1;
1340 }
1341
ths5fafdf22007-09-16 21:08:06 +00001342 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001343 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001344}
bellard8c6939c2003-06-09 15:28:00 +00001345#elif defined(__sparc__)
1346
ths5fafdf22007-09-16 21:08:06 +00001347int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001348 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001349{
ths5a7b5422007-01-31 12:16:51 +00001350 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001351 int is_write;
1352 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001353#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001354 uint32_t *regs = (uint32_t *)(info + 1);
1355 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001356 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001357 unsigned long pc = regs[1];
1358#else
blueswir184778502008-10-26 20:33:16 +00001359#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001360 struct sigcontext *sc = puc;
1361 unsigned long pc = sc->sigc_regs.tpc;
1362 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001363#elif defined(__OpenBSD__)
1364 struct sigcontext *uc = puc;
1365 unsigned long pc = uc->sc_pc;
1366 void *sigmask = (void *)(long)uc->sc_mask;
1367#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001368#endif
1369
bellard8c6939c2003-06-09 15:28:00 +00001370 /* XXX: need kernel patch to get write flag faster */
1371 is_write = 0;
1372 insn = *(uint32_t *)pc;
1373 if ((insn >> 30) == 3) {
1374 switch((insn >> 19) & 0x3f) {
1375 case 0x05: // stb
1376 case 0x06: // sth
1377 case 0x04: // st
1378 case 0x07: // std
1379 case 0x24: // stf
1380 case 0x27: // stdf
1381 case 0x25: // stfsr
1382 is_write = 1;
1383 break;
1384 }
1385 }
ths5fafdf22007-09-16 21:08:06 +00001386 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001387 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001388}
1389
1390#elif defined(__arm__)
1391
ths5fafdf22007-09-16 21:08:06 +00001392int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001393 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001394{
ths5a7b5422007-01-31 12:16:51 +00001395 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001396 struct ucontext *uc = puc;
1397 unsigned long pc;
1398 int is_write;
ths3b46e622007-09-17 08:09:54 +00001399
blueswir148bbf112008-07-08 18:35:02 +00001400#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001401 pc = uc->uc_mcontext.gregs[R15];
1402#else
balrog4eee57f2008-05-06 14:47:19 +00001403 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001404#endif
bellard8c6939c2003-06-09 15:28:00 +00001405 /* XXX: compute is_write */
1406 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001407 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001408 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001409 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001410}
1411
bellard38e584a2003-08-10 22:14:22 +00001412#elif defined(__mc68000)
1413
ths5fafdf22007-09-16 21:08:06 +00001414int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001415 void *puc)
1416{
ths5a7b5422007-01-31 12:16:51 +00001417 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001418 struct ucontext *uc = puc;
1419 unsigned long pc;
1420 int is_write;
ths3b46e622007-09-17 08:09:54 +00001421
bellard38e584a2003-08-10 22:14:22 +00001422 pc = uc->uc_mcontext.gregs[16];
1423 /* XXX: compute is_write */
1424 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001425 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001426 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001427 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001428}
1429
bellardb8076a72005-04-07 22:20:31 +00001430#elif defined(__ia64)
1431
1432#ifndef __ISR_VALID
1433 /* This ought to be in <bits/siginfo.h>... */
1434# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001435#endif
1436
ths5a7b5422007-01-31 12:16:51 +00001437int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001438{
ths5a7b5422007-01-31 12:16:51 +00001439 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001440 struct ucontext *uc = puc;
1441 unsigned long ip;
1442 int is_write = 0;
1443
1444 ip = uc->uc_mcontext.sc_ip;
1445 switch (host_signum) {
1446 case SIGILL:
1447 case SIGFPE:
1448 case SIGSEGV:
1449 case SIGBUS:
1450 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001451 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001452 /* ISR.W (write-access) is bit 33: */
1453 is_write = (info->si_isr >> 33) & 1;
1454 break;
1455
1456 default:
1457 break;
1458 }
1459 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1460 is_write,
1461 &uc->uc_sigmask, puc);
1462}
1463
bellard90cb9492005-07-24 15:11:38 +00001464#elif defined(__s390__)
1465
ths5fafdf22007-09-16 21:08:06 +00001466int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001467 void *puc)
1468{
ths5a7b5422007-01-31 12:16:51 +00001469 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001470 struct ucontext *uc = puc;
1471 unsigned long pc;
1472 int is_write;
ths3b46e622007-09-17 08:09:54 +00001473
bellard90cb9492005-07-24 15:11:38 +00001474 pc = uc->uc_mcontext.psw.addr;
1475 /* XXX: compute is_write */
1476 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001477 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001478 is_write, &uc->uc_sigmask, puc);
1479}
1480
1481#elif defined(__mips__)
1482
ths5fafdf22007-09-16 21:08:06 +00001483int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001484 void *puc)
1485{
ths9617efe2007-05-08 21:05:55 +00001486 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001487 struct ucontext *uc = puc;
1488 greg_t pc = uc->uc_mcontext.pc;
1489 int is_write;
ths3b46e622007-09-17 08:09:54 +00001490
thsc4b89d12007-05-05 19:23:11 +00001491 /* XXX: compute is_write */
1492 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001493 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001494 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001495}
1496
aurel32f54b3f92008-04-12 20:14:54 +00001497#elif defined(__hppa__)
1498
1499int cpu_signal_handler(int host_signum, void *pinfo,
1500 void *puc)
1501{
1502 struct siginfo *info = pinfo;
1503 struct ucontext *uc = puc;
1504 unsigned long pc;
1505 int is_write;
1506
1507 pc = uc->uc_mcontext.sc_iaoq[0];
1508 /* FIXME: compute is_write */
1509 is_write = 0;
1510 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1511 is_write,
1512 &uc->uc_sigmask, puc);
1513}
1514
bellard2b413142003-05-14 23:01:10 +00001515#else
1516
bellard3fb2ded2003-06-24 13:22:59 +00001517#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001518
1519#endif
bellard67b915a2004-03-31 23:37:16 +00001520
1521#endif /* !defined(CONFIG_SOFTMMU) */