]> git.proxmox.com Git - qemu.git/blob - cpu-exec.c
ARMv7 support.
[qemu.git] / cpu-exec.c
1 /*
2 * i386 emulator main execution loop
3 *
4 * Copyright (c) 2003-2005 Fabrice Bellard
5 *
6 * 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.
10 *
11 * 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.
15 *
16 * 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
19 */
20 #include "config.h"
21 #include "exec.h"
22 #include "disas.h"
23
24 #if !defined(CONFIG_SOFTMMU)
25 #undef EAX
26 #undef ECX
27 #undef EDX
28 #undef EBX
29 #undef ESP
30 #undef EBP
31 #undef ESI
32 #undef EDI
33 #undef EIP
34 #include <signal.h>
35 #include <sys/ucontext.h>
36 #endif
37
38 int tb_invalidated_flag;
39
40 //#define DEBUG_EXEC
41 //#define DEBUG_SIGNAL
42
43 void cpu_loop_exit(void)
44 {
45 /* NOTE: the register at this point must be saved by hand because
46 longjmp restore them */
47 regs_to_env();
48 longjmp(env->jmp_env, 1);
49 }
50
51 #if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
52 #define reg_T2
53 #endif
54
55 /* exit the current TB from a signal handler. The host registers are
56 restored in a state compatible with the CPU emulator
57 */
58 void cpu_resume_from_signal(CPUState *env1, void *puc)
59 {
60 #if !defined(CONFIG_SOFTMMU)
61 struct ucontext *uc = puc;
62 #endif
63
64 env = env1;
65
66 /* XXX: restore cpu registers saved in host registers */
67
68 #if !defined(CONFIG_SOFTMMU)
69 if (puc) {
70 /* XXX: use siglongjmp ? */
71 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
72 }
73 #endif
74 longjmp(env->jmp_env, 1);
75 }
76
77
78 static TranslationBlock *tb_find_slow(target_ulong pc,
79 target_ulong cs_base,
80 uint64_t flags)
81 {
82 TranslationBlock *tb, **ptb1;
83 int code_gen_size;
84 unsigned int h;
85 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
86 uint8_t *tc_ptr;
87
88 spin_lock(&tb_lock);
89
90 tb_invalidated_flag = 0;
91
92 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
93
94 /* find translated block using physical mappings */
95 phys_pc = get_phys_addr_code(env, pc);
96 phys_page1 = phys_pc & TARGET_PAGE_MASK;
97 phys_page2 = -1;
98 h = tb_phys_hash_func(phys_pc);
99 ptb1 = &tb_phys_hash[h];
100 for(;;) {
101 tb = *ptb1;
102 if (!tb)
103 goto not_found;
104 if (tb->pc == pc &&
105 tb->page_addr[0] == phys_page1 &&
106 tb->cs_base == cs_base &&
107 tb->flags == flags) {
108 /* check next page if needed */
109 if (tb->page_addr[1] != -1) {
110 virt_page2 = (pc & TARGET_PAGE_MASK) +
111 TARGET_PAGE_SIZE;
112 phys_page2 = get_phys_addr_code(env, virt_page2);
113 if (tb->page_addr[1] == phys_page2)
114 goto found;
115 } else {
116 goto found;
117 }
118 }
119 ptb1 = &tb->phys_hash_next;
120 }
121 not_found:
122 /* if no translated code available, then translate it now */
123 tb = tb_alloc(pc);
124 if (!tb) {
125 /* flush must be done */
126 tb_flush(env);
127 /* cannot fail at this point */
128 tb = tb_alloc(pc);
129 /* don't forget to invalidate previous TB info */
130 tb_invalidated_flag = 1;
131 }
132 tc_ptr = code_gen_ptr;
133 tb->tc_ptr = tc_ptr;
134 tb->cs_base = cs_base;
135 tb->flags = flags;
136 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
137 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
138
139 /* check next page if needed */
140 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
141 phys_page2 = -1;
142 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
143 phys_page2 = get_phys_addr_code(env, virt_page2);
144 }
145 tb_link_phys(tb, phys_pc, phys_page2);
146
147 found:
148 /* we add the TB in the virtual pc hash table */
149 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
150 spin_unlock(&tb_lock);
151 return tb;
152 }
153
154 static inline TranslationBlock *tb_find_fast(void)
155 {
156 TranslationBlock *tb;
157 target_ulong cs_base, pc;
158 uint64_t flags;
159
160 /* we record a subset of the CPU state. It will
161 always be the same before a given translated block
162 is executed. */
163 #if defined(TARGET_I386)
164 flags = env->hflags;
165 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
166 flags |= env->intercept;
167 cs_base = env->segs[R_CS].base;
168 pc = cs_base + env->eip;
169 #elif defined(TARGET_ARM)
170 flags = env->thumb | (env->vfp.vec_len << 1)
171 | (env->vfp.vec_stride << 4);
172 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
173 flags |= (1 << 6);
174 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
175 flags |= (1 << 7);
176 flags |= (env->condexec_bits << 8);
177 cs_base = 0;
178 pc = env->regs[15];
179 #elif defined(TARGET_SPARC)
180 #ifdef TARGET_SPARC64
181 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
182 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
183 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
184 #else
185 // FPU enable . Supervisor
186 flags = (env->psref << 4) | env->psrs;
187 #endif
188 cs_base = env->npc;
189 pc = env->pc;
190 #elif defined(TARGET_PPC)
191 flags = env->hflags;
192 cs_base = 0;
193 pc = env->nip;
194 #elif defined(TARGET_MIPS)
195 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
196 cs_base = 0;
197 pc = env->PC[env->current_tc];
198 #elif defined(TARGET_M68K)
199 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
200 | (env->sr & SR_S) /* Bit 13 */
201 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
202 cs_base = 0;
203 pc = env->pc;
204 #elif defined(TARGET_SH4)
205 flags = env->sr & (SR_MD | SR_RB);
206 cs_base = 0; /* XXXXX */
207 pc = env->pc;
208 #elif defined(TARGET_ALPHA)
209 flags = env->ps;
210 cs_base = 0;
211 pc = env->pc;
212 #elif defined(TARGET_CRIS)
213 flags = 0;
214 cs_base = 0;
215 pc = env->pc;
216 #else
217 #error unsupported CPU
218 #endif
219 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
220 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
221 tb->flags != flags, 0)) {
222 tb = tb_find_slow(pc, cs_base, flags);
223 /* Note: we do it here to avoid a gcc bug on Mac OS X when
224 doing it in tb_find_slow */
225 if (tb_invalidated_flag) {
226 /* as some TB could have been invalidated because
227 of memory exceptions while generating the code, we
228 must recompute the hash index here */
229 T0 = 0;
230 }
231 }
232 return tb;
233 }
234
235
236 /* main execution loop */
237
238 int cpu_exec(CPUState *env1)
239 {
240 #define DECLARE_HOST_REGS 1
241 #include "hostregs_helper.h"
242 #if defined(TARGET_SPARC)
243 #if defined(reg_REGWPTR)
244 uint32_t *saved_regwptr;
245 #endif
246 #endif
247 #if defined(__sparc__) && !defined(HOST_SOLARIS)
248 int saved_i7;
249 target_ulong tmp_T0;
250 #endif
251 int ret, interrupt_request;
252 void (*gen_func)(void);
253 TranslationBlock *tb;
254 uint8_t *tc_ptr;
255
256 if (cpu_halted(env1) == EXCP_HALTED)
257 return EXCP_HALTED;
258
259 cpu_single_env = env1;
260
261 /* first we save global registers */
262 #define SAVE_HOST_REGS 1
263 #include "hostregs_helper.h"
264 env = env1;
265 #if defined(__sparc__) && !defined(HOST_SOLARIS)
266 /* we also save i7 because longjmp may not restore it */
267 asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
268 #endif
269
270 env_to_regs();
271 #if defined(TARGET_I386)
272 /* put eflags in CPU temporary format */
273 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
274 DF = 1 - (2 * ((env->eflags >> 10) & 1));
275 CC_OP = CC_OP_EFLAGS;
276 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
277 #elif defined(TARGET_SPARC)
278 #if defined(reg_REGWPTR)
279 saved_regwptr = REGWPTR;
280 #endif
281 #elif defined(TARGET_M68K)
282 env->cc_op = CC_OP_FLAGS;
283 env->cc_dest = env->sr & 0xf;
284 env->cc_x = (env->sr >> 4) & 1;
285 #elif defined(TARGET_ALPHA)
286 #elif defined(TARGET_ARM)
287 #elif defined(TARGET_PPC)
288 #elif defined(TARGET_MIPS)
289 #elif defined(TARGET_SH4)
290 #elif defined(TARGET_CRIS)
291 /* XXXXX */
292 #else
293 #error unsupported target CPU
294 #endif
295 env->exception_index = -1;
296
297 /* prepare setjmp context for exception handling */
298 for(;;) {
299 if (setjmp(env->jmp_env) == 0) {
300 env->current_tb = NULL;
301 /* if an exception is pending, we execute it here */
302 if (env->exception_index >= 0) {
303 if (env->exception_index >= EXCP_INTERRUPT) {
304 /* exit request from the cpu execution loop */
305 ret = env->exception_index;
306 break;
307 } else if (env->user_mode_only) {
308 /* if user mode only, we simulate a fake exception
309 which will be handled outside the cpu execution
310 loop */
311 #if defined(TARGET_I386)
312 do_interrupt_user(env->exception_index,
313 env->exception_is_int,
314 env->error_code,
315 env->exception_next_eip);
316 #endif
317 ret = env->exception_index;
318 break;
319 } else {
320 #if defined(TARGET_I386)
321 /* simulate a real cpu exception. On i386, it can
322 trigger new exceptions, but we do not handle
323 double or triple faults yet. */
324 do_interrupt(env->exception_index,
325 env->exception_is_int,
326 env->error_code,
327 env->exception_next_eip, 0);
328 /* successfully delivered */
329 env->old_exception = -1;
330 #elif defined(TARGET_PPC)
331 do_interrupt(env);
332 #elif defined(TARGET_MIPS)
333 do_interrupt(env);
334 #elif defined(TARGET_SPARC)
335 do_interrupt(env->exception_index);
336 #elif defined(TARGET_ARM)
337 do_interrupt(env);
338 #elif defined(TARGET_SH4)
339 do_interrupt(env);
340 #elif defined(TARGET_ALPHA)
341 do_interrupt(env);
342 #elif defined(TARGET_CRIS)
343 do_interrupt(env);
344 #elif defined(TARGET_M68K)
345 do_interrupt(0);
346 #endif
347 }
348 env->exception_index = -1;
349 }
350 #ifdef USE_KQEMU
351 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
352 int ret;
353 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
354 ret = kqemu_cpu_exec(env);
355 /* put eflags in CPU temporary format */
356 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
357 DF = 1 - (2 * ((env->eflags >> 10) & 1));
358 CC_OP = CC_OP_EFLAGS;
359 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
360 if (ret == 1) {
361 /* exception */
362 longjmp(env->jmp_env, 1);
363 } else if (ret == 2) {
364 /* softmmu execution needed */
365 } else {
366 if (env->interrupt_request != 0) {
367 /* hardware interrupt will be executed just after */
368 } else {
369 /* otherwise, we restart */
370 longjmp(env->jmp_env, 1);
371 }
372 }
373 }
374 #endif
375
376 T0 = 0; /* force lookup of first TB */
377 for(;;) {
378 #if defined(__sparc__) && !defined(HOST_SOLARIS)
379 /* g1 can be modified by some libc? functions */
380 tmp_T0 = T0;
381 #endif
382 interrupt_request = env->interrupt_request;
383 if (__builtin_expect(interrupt_request, 0)
384 #if defined(TARGET_I386)
385 && env->hflags & HF_GIF_MASK
386 #endif
387 ) {
388 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
389 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
390 env->exception_index = EXCP_DEBUG;
391 cpu_loop_exit();
392 }
393 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
394 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
395 if (interrupt_request & CPU_INTERRUPT_HALT) {
396 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
397 env->halted = 1;
398 env->exception_index = EXCP_HLT;
399 cpu_loop_exit();
400 }
401 #endif
402 #if defined(TARGET_I386)
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 #if defined(__sparc__) && !defined(HOST_SOLARIS)
409 tmp_T0 = 0;
410 #else
411 T0 = 0;
412 #endif
413 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
414 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
415 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
416 int intno;
417 svm_check_intercept(SVM_EXIT_INTR);
418 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
419 intno = cpu_get_pic_interrupt(env);
420 if (loglevel & CPU_LOG_TB_IN_ASM) {
421 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
422 }
423 do_interrupt(intno, 0, 0, 0, 1);
424 /* ensure that no TB jump will be modified as
425 the program flow was changed */
426 #if defined(__sparc__) && !defined(HOST_SOLARIS)
427 tmp_T0 = 0;
428 #else
429 T0 = 0;
430 #endif
431 #if !defined(CONFIG_USER_ONLY)
432 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
433 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
434 int intno;
435 /* FIXME: this should respect TPR */
436 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
437 svm_check_intercept(SVM_EXIT_VINTR);
438 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
439 if (loglevel & CPU_LOG_TB_IN_ASM)
440 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
441 do_interrupt(intno, 0, 0, -1, 1);
442 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
443 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
444 #if defined(__sparc__) && !defined(HOST_SOLARIS)
445 tmp_T0 = 0;
446 #else
447 T0 = 0;
448 #endif
449 #endif
450 }
451 #elif defined(TARGET_PPC)
452 #if 0
453 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
454 cpu_ppc_reset(env);
455 }
456 #endif
457 if (interrupt_request & CPU_INTERRUPT_HARD) {
458 ppc_hw_interrupt(env);
459 if (env->pending_interrupts == 0)
460 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
461 #if defined(__sparc__) && !defined(HOST_SOLARIS)
462 tmp_T0 = 0;
463 #else
464 T0 = 0;
465 #endif
466 }
467 #elif defined(TARGET_MIPS)
468 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
469 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
470 (env->CP0_Status & (1 << CP0St_IE)) &&
471 !(env->CP0_Status & (1 << CP0St_EXL)) &&
472 !(env->CP0_Status & (1 << CP0St_ERL)) &&
473 !(env->hflags & MIPS_HFLAG_DM)) {
474 /* Raise it */
475 env->exception_index = EXCP_EXT_INTERRUPT;
476 env->error_code = 0;
477 do_interrupt(env);
478 #if defined(__sparc__) && !defined(HOST_SOLARIS)
479 tmp_T0 = 0;
480 #else
481 T0 = 0;
482 #endif
483 }
484 #elif defined(TARGET_SPARC)
485 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
486 (env->psret != 0)) {
487 int pil = env->interrupt_index & 15;
488 int type = env->interrupt_index & 0xf0;
489
490 if (((type == TT_EXTINT) &&
491 (pil == 15 || pil > env->psrpil)) ||
492 type != TT_EXTINT) {
493 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
494 do_interrupt(env->interrupt_index);
495 env->interrupt_index = 0;
496 #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
497 cpu_check_irqs(env);
498 #endif
499 #if defined(__sparc__) && !defined(HOST_SOLARIS)
500 tmp_T0 = 0;
501 #else
502 T0 = 0;
503 #endif
504 }
505 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
506 //do_interrupt(0, 0, 0, 0, 0);
507 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
508 }
509 #elif defined(TARGET_ARM)
510 if (interrupt_request & CPU_INTERRUPT_FIQ
511 && !(env->uncached_cpsr & CPSR_F)) {
512 env->exception_index = EXCP_FIQ;
513 do_interrupt(env);
514 }
515 /* ARMv7-M interrupt return works by loading a magic value
516 into the PC. On real hardware the load causes the
517 return to occur. The qemu implementation performs the
518 jump normally, then does the exception return when the
519 CPU tries to execute code at the magic address.
520 This will cause the magic PC value to be pushed to
521 the stack if an interrupt occured at the wrong time.
522 We avoid this by disabling interrupts when
523 pc contains a magic address. */
524 if (interrupt_request & CPU_INTERRUPT_HARD
525 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
526 || !(env->uncached_cpsr & CPSR_I))) {
527 env->exception_index = EXCP_IRQ;
528 do_interrupt(env);
529 }
530 #elif defined(TARGET_SH4)
531 /* XXXXX */
532 #elif defined(TARGET_ALPHA)
533 if (interrupt_request & CPU_INTERRUPT_HARD) {
534 do_interrupt(env);
535 }
536 #elif defined(TARGET_CRIS)
537 if (interrupt_request & CPU_INTERRUPT_HARD) {
538 do_interrupt(env);
539 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
540 }
541 #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);
552 }
553 #endif
554 /* Don't use the cached interupt_request value,
555 do_interrupt may have updated the EXITTB flag. */
556 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
557 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
558 /* ensure that no TB jump will be modified as
559 the program flow was changed */
560 #if defined(__sparc__) && !defined(HOST_SOLARIS)
561 tmp_T0 = 0;
562 #else
563 T0 = 0;
564 #endif
565 }
566 if (interrupt_request & CPU_INTERRUPT_EXIT) {
567 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
568 env->exception_index = EXCP_INTERRUPT;
569 cpu_loop_exit();
570 }
571 }
572 #ifdef DEBUG_EXEC
573 if ((loglevel & CPU_LOG_TB_CPU)) {
574 /* restore flags in standard format */
575 regs_to_env();
576 #if defined(TARGET_I386)
577 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
578 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
579 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
580 #elif defined(TARGET_ARM)
581 cpu_dump_state(env, logfile, fprintf, 0);
582 #elif defined(TARGET_SPARC)
583 REGWPTR = env->regbase + (env->cwp * 16);
584 env->regwptr = REGWPTR;
585 cpu_dump_state(env, logfile, fprintf, 0);
586 #elif defined(TARGET_PPC)
587 cpu_dump_state(env, logfile, fprintf, 0);
588 #elif defined(TARGET_M68K)
589 cpu_m68k_flush_flags(env, env->cc_op);
590 env->cc_op = CC_OP_FLAGS;
591 env->sr = (env->sr & 0xffe0)
592 | env->cc_dest | (env->cc_x << 4);
593 cpu_dump_state(env, logfile, fprintf, 0);
594 #elif defined(TARGET_MIPS)
595 cpu_dump_state(env, logfile, fprintf, 0);
596 #elif defined(TARGET_SH4)
597 cpu_dump_state(env, logfile, fprintf, 0);
598 #elif defined(TARGET_ALPHA)
599 cpu_dump_state(env, logfile, fprintf, 0);
600 #elif defined(TARGET_CRIS)
601 cpu_dump_state(env, logfile, fprintf, 0);
602 #else
603 #error unsupported target CPU
604 #endif
605 }
606 #endif
607 tb = tb_find_fast();
608 #ifdef DEBUG_EXEC
609 if ((loglevel & CPU_LOG_EXEC)) {
610 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
611 (long)tb->tc_ptr, tb->pc,
612 lookup_symbol(tb->pc));
613 }
614 #endif
615 #if defined(__sparc__) && !defined(HOST_SOLARIS)
616 T0 = tmp_T0;
617 #endif
618 /* see if we can patch the calling TB. When the TB
619 spans two pages, we cannot safely do a direct
620 jump. */
621 {
622 if (T0 != 0 &&
623 #if USE_KQEMU
624 (env->kqemu_enabled != 2) &&
625 #endif
626 tb->page_addr[1] == -1) {
627 spin_lock(&tb_lock);
628 tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
629 spin_unlock(&tb_lock);
630 }
631 }
632 tc_ptr = tb->tc_ptr;
633 env->current_tb = tb;
634 /* execute the generated code */
635 gen_func = (void *)tc_ptr;
636 #if defined(__sparc__)
637 __asm__ __volatile__("call %0\n\t"
638 "mov %%o7,%%i0"
639 : /* no outputs */
640 : "r" (gen_func)
641 : "i0", "i1", "i2", "i3", "i4", "i5",
642 "o0", "o1", "o2", "o3", "o4", "o5",
643 "l0", "l1", "l2", "l3", "l4", "l5",
644 "l6", "l7");
645 #elif defined(__arm__)
646 asm volatile ("mov pc, %0\n\t"
647 ".global exec_loop\n\t"
648 "exec_loop:\n\t"
649 : /* no outputs */
650 : "r" (gen_func)
651 : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
652 #elif defined(__ia64)
653 struct fptr {
654 void *ip;
655 void *gp;
656 } fp;
657
658 fp.ip = tc_ptr;
659 fp.gp = code_gen_buffer + 2 * (1 << 20);
660 (*(void (*)(void)) &fp)();
661 #else
662 gen_func();
663 #endif
664 env->current_tb = NULL;
665 /* reset soft MMU for next block (it can currently
666 only be set by a memory fault) */
667 #if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
668 if (env->hflags & HF_SOFTMMU_MASK) {
669 env->hflags &= ~HF_SOFTMMU_MASK;
670 /* do not allow linking to another block */
671 T0 = 0;
672 }
673 #endif
674 #if defined(USE_KQEMU)
675 #define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
676 if (kqemu_is_ok(env) &&
677 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
678 cpu_loop_exit();
679 }
680 #endif
681 } /* for(;;) */
682 } else {
683 env_to_regs();
684 }
685 } /* for(;;) */
686
687
688 #if defined(TARGET_I386)
689 /* restore flags in standard format */
690 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
691 #elif defined(TARGET_ARM)
692 /* XXX: Save/restore host fpu exception state?. */
693 #elif defined(TARGET_SPARC)
694 #if defined(reg_REGWPTR)
695 REGWPTR = saved_regwptr;
696 #endif
697 #elif defined(TARGET_PPC)
698 #elif defined(TARGET_M68K)
699 cpu_m68k_flush_flags(env, env->cc_op);
700 env->cc_op = CC_OP_FLAGS;
701 env->sr = (env->sr & 0xffe0)
702 | env->cc_dest | (env->cc_x << 4);
703 #elif defined(TARGET_MIPS)
704 #elif defined(TARGET_SH4)
705 #elif defined(TARGET_ALPHA)
706 #elif defined(TARGET_CRIS)
707 /* XXXXX */
708 #else
709 #error unsupported target CPU
710 #endif
711
712 /* restore global registers */
713 #if defined(__sparc__) && !defined(HOST_SOLARIS)
714 asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
715 #endif
716 #include "hostregs_helper.h"
717
718 /* fail safe : never use cpu_single_env outside cpu_exec() */
719 cpu_single_env = NULL;
720 return ret;
721 }
722
723 /* must only be called from the generated code as an exception can be
724 generated */
725 void tb_invalidate_page_range(target_ulong start, target_ulong end)
726 {
727 /* XXX: cannot enable it yet because it yields to MMU exception
728 where NIP != read address on PowerPC */
729 #if 0
730 target_ulong phys_addr;
731 phys_addr = get_phys_addr_code(env, start);
732 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
733 #endif
734 }
735
736 #if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
737
738 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
739 {
740 CPUX86State *saved_env;
741
742 saved_env = env;
743 env = s;
744 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
745 selector &= 0xffff;
746 cpu_x86_load_seg_cache(env, seg_reg, selector,
747 (selector << 4), 0xffff, 0);
748 } else {
749 load_seg(seg_reg, selector);
750 }
751 env = saved_env;
752 }
753
754 void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
755 {
756 CPUX86State *saved_env;
757
758 saved_env = env;
759 env = s;
760
761 helper_fsave((target_ulong)ptr, data32);
762
763 env = saved_env;
764 }
765
766 void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
767 {
768 CPUX86State *saved_env;
769
770 saved_env = env;
771 env = s;
772
773 helper_frstor((target_ulong)ptr, data32);
774
775 env = saved_env;
776 }
777
778 #endif /* TARGET_I386 */
779
780 #if !defined(CONFIG_SOFTMMU)
781
782 #if defined(TARGET_I386)
783
784 /* 'pc' is the host PC at which the exception was raised. 'address' is
785 the effective address of the memory exception. 'is_write' is 1 if a
786 write caused the exception and otherwise 0'. 'old_set' is the
787 signal set which should be restored */
788 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
789 int is_write, sigset_t *old_set,
790 void *puc)
791 {
792 TranslationBlock *tb;
793 int ret;
794
795 if (cpu_single_env)
796 env = cpu_single_env; /* XXX: find a correct solution for multithread */
797 #if defined(DEBUG_SIGNAL)
798 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
799 pc, address, is_write, *(unsigned long *)old_set);
800 #endif
801 /* XXX: locking issue */
802 if (is_write && page_unprotect(h2g(address), pc, puc)) {
803 return 1;
804 }
805
806 /* see if it is an MMU fault */
807 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
808 if (ret < 0)
809 return 0; /* not an MMU fault */
810 if (ret == 0)
811 return 1; /* the MMU fault was handled without causing real CPU fault */
812 /* now we have a real cpu fault */
813 tb = tb_find_pc(pc);
814 if (tb) {
815 /* the PC is inside the translated code. It means that we have
816 a virtual CPU fault */
817 cpu_restore_state(tb, env, pc, puc);
818 }
819 if (ret == 1) {
820 #if 0
821 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
822 env->eip, env->cr[2], env->error_code);
823 #endif
824 /* we restore the process signal mask as the sigreturn should
825 do it (XXX: use sigsetjmp) */
826 sigprocmask(SIG_SETMASK, old_set, NULL);
827 raise_exception_err(env->exception_index, env->error_code);
828 } else {
829 /* activate soft MMU for this block */
830 env->hflags |= HF_SOFTMMU_MASK;
831 cpu_resume_from_signal(env, puc);
832 }
833 /* never comes here */
834 return 1;
835 }
836
837 #elif defined(TARGET_ARM)
838 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
839 int is_write, sigset_t *old_set,
840 void *puc)
841 {
842 TranslationBlock *tb;
843 int ret;
844
845 if (cpu_single_env)
846 env = cpu_single_env; /* XXX: find a correct solution for multithread */
847 #if defined(DEBUG_SIGNAL)
848 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
849 pc, address, is_write, *(unsigned long *)old_set);
850 #endif
851 /* XXX: locking issue */
852 if (is_write && page_unprotect(h2g(address), pc, puc)) {
853 return 1;
854 }
855 /* see if it is an MMU fault */
856 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
857 if (ret < 0)
858 return 0; /* not an MMU fault */
859 if (ret == 0)
860 return 1; /* the MMU fault was handled without causing real CPU fault */
861 /* now we have a real cpu fault */
862 tb = tb_find_pc(pc);
863 if (tb) {
864 /* the PC is inside the translated code. It means that we have
865 a virtual CPU fault */
866 cpu_restore_state(tb, env, pc, puc);
867 }
868 /* we restore the process signal mask as the sigreturn should
869 do it (XXX: use sigsetjmp) */
870 sigprocmask(SIG_SETMASK, old_set, NULL);
871 cpu_loop_exit();
872 }
873 #elif defined(TARGET_SPARC)
874 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
875 int is_write, sigset_t *old_set,
876 void *puc)
877 {
878 TranslationBlock *tb;
879 int ret;
880
881 if (cpu_single_env)
882 env = cpu_single_env; /* XXX: find a correct solution for multithread */
883 #if defined(DEBUG_SIGNAL)
884 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
885 pc, address, is_write, *(unsigned long *)old_set);
886 #endif
887 /* XXX: locking issue */
888 if (is_write && page_unprotect(h2g(address), pc, puc)) {
889 return 1;
890 }
891 /* see if it is an MMU fault */
892 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
893 if (ret < 0)
894 return 0; /* not an MMU fault */
895 if (ret == 0)
896 return 1; /* the MMU fault was handled without causing real CPU fault */
897 /* now we have a real cpu fault */
898 tb = tb_find_pc(pc);
899 if (tb) {
900 /* the PC is inside the translated code. It means that we have
901 a virtual CPU fault */
902 cpu_restore_state(tb, env, pc, puc);
903 }
904 /* we restore the process signal mask as the sigreturn should
905 do it (XXX: use sigsetjmp) */
906 sigprocmask(SIG_SETMASK, old_set, NULL);
907 cpu_loop_exit();
908 }
909 #elif defined (TARGET_PPC)
910 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
911 int is_write, sigset_t *old_set,
912 void *puc)
913 {
914 TranslationBlock *tb;
915 int ret;
916
917 if (cpu_single_env)
918 env = cpu_single_env; /* XXX: find a correct solution for multithread */
919 #if defined(DEBUG_SIGNAL)
920 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
921 pc, address, is_write, *(unsigned long *)old_set);
922 #endif
923 /* XXX: locking issue */
924 if (is_write && page_unprotect(h2g(address), pc, puc)) {
925 return 1;
926 }
927
928 /* see if it is an MMU fault */
929 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
930 if (ret < 0)
931 return 0; /* not an MMU fault */
932 if (ret == 0)
933 return 1; /* the MMU fault was handled without causing real CPU fault */
934
935 /* now we have a real cpu fault */
936 tb = tb_find_pc(pc);
937 if (tb) {
938 /* the PC is inside the translated code. It means that we have
939 a virtual CPU fault */
940 cpu_restore_state(tb, env, pc, puc);
941 }
942 if (ret == 1) {
943 #if 0
944 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
945 env->nip, env->error_code, tb);
946 #endif
947 /* we restore the process signal mask as the sigreturn should
948 do it (XXX: use sigsetjmp) */
949 sigprocmask(SIG_SETMASK, old_set, NULL);
950 do_raise_exception_err(env->exception_index, env->error_code);
951 } else {
952 /* activate soft MMU for this block */
953 cpu_resume_from_signal(env, puc);
954 }
955 /* never comes here */
956 return 1;
957 }
958
959 #elif defined(TARGET_M68K)
960 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
961 int is_write, sigset_t *old_set,
962 void *puc)
963 {
964 TranslationBlock *tb;
965 int ret;
966
967 if (cpu_single_env)
968 env = cpu_single_env; /* XXX: find a correct solution for multithread */
969 #if defined(DEBUG_SIGNAL)
970 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
971 pc, address, is_write, *(unsigned long *)old_set);
972 #endif
973 /* XXX: locking issue */
974 if (is_write && page_unprotect(address, pc, puc)) {
975 return 1;
976 }
977 /* see if it is an MMU fault */
978 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
979 if (ret < 0)
980 return 0; /* not an MMU fault */
981 if (ret == 0)
982 return 1; /* the MMU fault was handled without causing real CPU fault */
983 /* now we have a real cpu fault */
984 tb = tb_find_pc(pc);
985 if (tb) {
986 /* the PC is inside the translated code. It means that we have
987 a virtual CPU fault */
988 cpu_restore_state(tb, env, pc, puc);
989 }
990 /* we restore the process signal mask as the sigreturn should
991 do it (XXX: use sigsetjmp) */
992 sigprocmask(SIG_SETMASK, old_set, NULL);
993 cpu_loop_exit();
994 /* never comes here */
995 return 1;
996 }
997
998 #elif defined (TARGET_MIPS)
999 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1000 int is_write, sigset_t *old_set,
1001 void *puc)
1002 {
1003 TranslationBlock *tb;
1004 int ret;
1005
1006 if (cpu_single_env)
1007 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1008 #if defined(DEBUG_SIGNAL)
1009 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1010 pc, address, is_write, *(unsigned long *)old_set);
1011 #endif
1012 /* XXX: locking issue */
1013 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1014 return 1;
1015 }
1016
1017 /* see if it is an MMU fault */
1018 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1019 if (ret < 0)
1020 return 0; /* not an MMU fault */
1021 if (ret == 0)
1022 return 1; /* the MMU fault was handled without causing real CPU fault */
1023
1024 /* now we have a real cpu fault */
1025 tb = tb_find_pc(pc);
1026 if (tb) {
1027 /* the PC is inside the translated code. It means that we have
1028 a virtual CPU fault */
1029 cpu_restore_state(tb, env, pc, puc);
1030 }
1031 if (ret == 1) {
1032 #if 0
1033 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
1034 env->PC, env->error_code, tb);
1035 #endif
1036 /* we restore the process signal mask as the sigreturn should
1037 do it (XXX: use sigsetjmp) */
1038 sigprocmask(SIG_SETMASK, old_set, NULL);
1039 do_raise_exception_err(env->exception_index, env->error_code);
1040 } else {
1041 /* activate soft MMU for this block */
1042 cpu_resume_from_signal(env, puc);
1043 }
1044 /* never comes here */
1045 return 1;
1046 }
1047
1048 #elif defined (TARGET_SH4)
1049 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1050 int is_write, sigset_t *old_set,
1051 void *puc)
1052 {
1053 TranslationBlock *tb;
1054 int ret;
1055
1056 if (cpu_single_env)
1057 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1058 #if defined(DEBUG_SIGNAL)
1059 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1060 pc, address, is_write, *(unsigned long *)old_set);
1061 #endif
1062 /* XXX: locking issue */
1063 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1064 return 1;
1065 }
1066
1067 /* see if it is an MMU fault */
1068 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1069 if (ret < 0)
1070 return 0; /* not an MMU fault */
1071 if (ret == 0)
1072 return 1; /* the MMU fault was handled without causing real CPU fault */
1073
1074 /* now we have a real cpu fault */
1075 tb = tb_find_pc(pc);
1076 if (tb) {
1077 /* the PC is inside the translated code. It means that we have
1078 a virtual CPU fault */
1079 cpu_restore_state(tb, env, pc, puc);
1080 }
1081 #if 0
1082 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1083 env->nip, env->error_code, tb);
1084 #endif
1085 /* we restore the process signal mask as the sigreturn should
1086 do it (XXX: use sigsetjmp) */
1087 sigprocmask(SIG_SETMASK, old_set, NULL);
1088 cpu_loop_exit();
1089 /* never comes here */
1090 return 1;
1091 }
1092
1093 #elif defined (TARGET_ALPHA)
1094 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1095 int is_write, sigset_t *old_set,
1096 void *puc)
1097 {
1098 TranslationBlock *tb;
1099 int ret;
1100
1101 if (cpu_single_env)
1102 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1103 #if defined(DEBUG_SIGNAL)
1104 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1105 pc, address, is_write, *(unsigned long *)old_set);
1106 #endif
1107 /* XXX: locking issue */
1108 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1109 return 1;
1110 }
1111
1112 /* see if it is an MMU fault */
1113 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1114 if (ret < 0)
1115 return 0; /* not an MMU fault */
1116 if (ret == 0)
1117 return 1; /* the MMU fault was handled without causing real CPU fault */
1118
1119 /* now we have a real cpu fault */
1120 tb = tb_find_pc(pc);
1121 if (tb) {
1122 /* the PC is inside the translated code. It means that we have
1123 a virtual CPU fault */
1124 cpu_restore_state(tb, env, pc, puc);
1125 }
1126 #if 0
1127 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1128 env->nip, env->error_code, tb);
1129 #endif
1130 /* we restore the process signal mask as the sigreturn should
1131 do it (XXX: use sigsetjmp) */
1132 sigprocmask(SIG_SETMASK, old_set, NULL);
1133 cpu_loop_exit();
1134 /* never comes here */
1135 return 1;
1136 }
1137 #elif defined (TARGET_CRIS)
1138 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1139 int is_write, sigset_t *old_set,
1140 void *puc)
1141 {
1142 TranslationBlock *tb;
1143 int ret;
1144
1145 if (cpu_single_env)
1146 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1147 #if defined(DEBUG_SIGNAL)
1148 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1149 pc, address, is_write, *(unsigned long *)old_set);
1150 #endif
1151 /* XXX: locking issue */
1152 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1153 return 1;
1154 }
1155
1156 /* see if it is an MMU fault */
1157 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1158 if (ret < 0)
1159 return 0; /* not an MMU fault */
1160 if (ret == 0)
1161 return 1; /* the MMU fault was handled without causing real CPU fault */
1162
1163 /* now we have a real cpu fault */
1164 tb = tb_find_pc(pc);
1165 if (tb) {
1166 /* the PC is inside the translated code. It means that we have
1167 a virtual CPU fault */
1168 cpu_restore_state(tb, env, pc, puc);
1169 }
1170 #if 0
1171 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1172 env->nip, env->error_code, tb);
1173 #endif
1174 /* we restore the process signal mask as the sigreturn should
1175 do it (XXX: use sigsetjmp) */
1176 sigprocmask(SIG_SETMASK, old_set, NULL);
1177 cpu_loop_exit();
1178 /* never comes here */
1179 return 1;
1180 }
1181
1182 #else
1183 #error unsupported target CPU
1184 #endif
1185
1186 #if defined(__i386__)
1187
1188 #if defined(__APPLE__)
1189 # include <sys/ucontext.h>
1190
1191 # define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1192 # define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1193 # define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1194 #else
1195 # define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1196 # define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1197 # define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1198 #endif
1199
1200 int cpu_signal_handler(int host_signum, void *pinfo,
1201 void *puc)
1202 {
1203 siginfo_t *info = pinfo;
1204 struct ucontext *uc = puc;
1205 unsigned long pc;
1206 int trapno;
1207
1208 #ifndef REG_EIP
1209 /* for glibc 2.1 */
1210 #define REG_EIP EIP
1211 #define REG_ERR ERR
1212 #define REG_TRAPNO TRAPNO
1213 #endif
1214 pc = EIP_sig(uc);
1215 trapno = TRAP_sig(uc);
1216 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1217 trapno == 0xe ?
1218 (ERROR_sig(uc) >> 1) & 1 : 0,
1219 &uc->uc_sigmask, puc);
1220 }
1221
1222 #elif defined(__x86_64__)
1223
1224 int cpu_signal_handler(int host_signum, void *pinfo,
1225 void *puc)
1226 {
1227 siginfo_t *info = pinfo;
1228 struct ucontext *uc = puc;
1229 unsigned long pc;
1230
1231 pc = uc->uc_mcontext.gregs[REG_RIP];
1232 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1233 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
1234 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1235 &uc->uc_sigmask, puc);
1236 }
1237
1238 #elif defined(__powerpc__)
1239
1240 /***********************************************************************
1241 * signal context platform-specific definitions
1242 * From Wine
1243 */
1244 #ifdef linux
1245 /* All Registers access - only for local access */
1246 # define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1247 /* Gpr Registers access */
1248 # define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1249 # define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1250 # define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1251 # define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1252 # define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1253 # define LR_sig(context) REG_sig(link, context) /* Link register */
1254 # define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1255 /* Float Registers access */
1256 # define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1257 # define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1258 /* Exception Registers access */
1259 # define DAR_sig(context) REG_sig(dar, context)
1260 # define DSISR_sig(context) REG_sig(dsisr, context)
1261 # define TRAP_sig(context) REG_sig(trap, context)
1262 #endif /* linux */
1263
1264 #ifdef __APPLE__
1265 # include <sys/ucontext.h>
1266 typedef struct ucontext SIGCONTEXT;
1267 /* All Registers access - only for local access */
1268 # define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1269 # define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1270 # define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1271 # define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1272 /* Gpr Registers access */
1273 # define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1274 # define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1275 # define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1276 # define CTR_sig(context) REG_sig(ctr, context)
1277 # define XER_sig(context) REG_sig(xer, context) /* Link register */
1278 # define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1279 # define CR_sig(context) REG_sig(cr, context) /* Condition register */
1280 /* Float Registers access */
1281 # define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1282 # define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1283 /* Exception Registers access */
1284 # define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1285 # define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1286 # define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1287 #endif /* __APPLE__ */
1288
1289 int cpu_signal_handler(int host_signum, void *pinfo,
1290 void *puc)
1291 {
1292 siginfo_t *info = pinfo;
1293 struct ucontext *uc = puc;
1294 unsigned long pc;
1295 int is_write;
1296
1297 pc = IAR_sig(uc);
1298 is_write = 0;
1299 #if 0
1300 /* ppc 4xx case */
1301 if (DSISR_sig(uc) & 0x00800000)
1302 is_write = 1;
1303 #else
1304 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1305 is_write = 1;
1306 #endif
1307 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1308 is_write, &uc->uc_sigmask, puc);
1309 }
1310
1311 #elif defined(__alpha__)
1312
1313 int cpu_signal_handler(int host_signum, void *pinfo,
1314 void *puc)
1315 {
1316 siginfo_t *info = pinfo;
1317 struct ucontext *uc = puc;
1318 uint32_t *pc = uc->uc_mcontext.sc_pc;
1319 uint32_t insn = *pc;
1320 int is_write = 0;
1321
1322 /* XXX: need kernel patch to get write flag faster */
1323 switch (insn >> 26) {
1324 case 0x0d: // stw
1325 case 0x0e: // stb
1326 case 0x0f: // stq_u
1327 case 0x24: // stf
1328 case 0x25: // stg
1329 case 0x26: // sts
1330 case 0x27: // stt
1331 case 0x2c: // stl
1332 case 0x2d: // stq
1333 case 0x2e: // stl_c
1334 case 0x2f: // stq_c
1335 is_write = 1;
1336 }
1337
1338 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1339 is_write, &uc->uc_sigmask, puc);
1340 }
1341 #elif defined(__sparc__)
1342
1343 int cpu_signal_handler(int host_signum, void *pinfo,
1344 void *puc)
1345 {
1346 siginfo_t *info = pinfo;
1347 uint32_t *regs = (uint32_t *)(info + 1);
1348 void *sigmask = (regs + 20);
1349 unsigned long pc;
1350 int is_write;
1351 uint32_t insn;
1352
1353 /* XXX: is there a standard glibc define ? */
1354 pc = regs[1];
1355 /* XXX: need kernel patch to get write flag faster */
1356 is_write = 0;
1357 insn = *(uint32_t *)pc;
1358 if ((insn >> 30) == 3) {
1359 switch((insn >> 19) & 0x3f) {
1360 case 0x05: // stb
1361 case 0x06: // sth
1362 case 0x04: // st
1363 case 0x07: // std
1364 case 0x24: // stf
1365 case 0x27: // stdf
1366 case 0x25: // stfsr
1367 is_write = 1;
1368 break;
1369 }
1370 }
1371 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1372 is_write, sigmask, NULL);
1373 }
1374
1375 #elif defined(__arm__)
1376
1377 int cpu_signal_handler(int host_signum, void *pinfo,
1378 void *puc)
1379 {
1380 siginfo_t *info = pinfo;
1381 struct ucontext *uc = puc;
1382 unsigned long pc;
1383 int is_write;
1384
1385 pc = uc->uc_mcontext.gregs[R15];
1386 /* XXX: compute is_write */
1387 is_write = 0;
1388 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1389 is_write,
1390 &uc->uc_sigmask, puc);
1391 }
1392
1393 #elif defined(__mc68000)
1394
1395 int cpu_signal_handler(int host_signum, void *pinfo,
1396 void *puc)
1397 {
1398 siginfo_t *info = pinfo;
1399 struct ucontext *uc = puc;
1400 unsigned long pc;
1401 int is_write;
1402
1403 pc = uc->uc_mcontext.gregs[16];
1404 /* XXX: compute is_write */
1405 is_write = 0;
1406 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1407 is_write,
1408 &uc->uc_sigmask, puc);
1409 }
1410
1411 #elif defined(__ia64)
1412
1413 #ifndef __ISR_VALID
1414 /* This ought to be in <bits/siginfo.h>... */
1415 # define __ISR_VALID 1
1416 #endif
1417
1418 int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1419 {
1420 siginfo_t *info = pinfo;
1421 struct ucontext *uc = puc;
1422 unsigned long ip;
1423 int is_write = 0;
1424
1425 ip = uc->uc_mcontext.sc_ip;
1426 switch (host_signum) {
1427 case SIGILL:
1428 case SIGFPE:
1429 case SIGSEGV:
1430 case SIGBUS:
1431 case SIGTRAP:
1432 if (info->si_code && (info->si_segvflags & __ISR_VALID))
1433 /* ISR.W (write-access) is bit 33: */
1434 is_write = (info->si_isr >> 33) & 1;
1435 break;
1436
1437 default:
1438 break;
1439 }
1440 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1441 is_write,
1442 &uc->uc_sigmask, puc);
1443 }
1444
1445 #elif defined(__s390__)
1446
1447 int cpu_signal_handler(int host_signum, void *pinfo,
1448 void *puc)
1449 {
1450 siginfo_t *info = pinfo;
1451 struct ucontext *uc = puc;
1452 unsigned long pc;
1453 int is_write;
1454
1455 pc = uc->uc_mcontext.psw.addr;
1456 /* XXX: compute is_write */
1457 is_write = 0;
1458 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1459 is_write, &uc->uc_sigmask, puc);
1460 }
1461
1462 #elif defined(__mips__)
1463
1464 int cpu_signal_handler(int host_signum, void *pinfo,
1465 void *puc)
1466 {
1467 siginfo_t *info = pinfo;
1468 struct ucontext *uc = puc;
1469 greg_t pc = uc->uc_mcontext.pc;
1470 int is_write;
1471
1472 /* XXX: compute is_write */
1473 is_write = 0;
1474 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1475 is_write, &uc->uc_sigmask, puc);
1476 }
1477
1478 #else
1479
1480 #error host CPU specific signal handler needed
1481
1482 #endif
1483
1484 #endif /* !defined(CONFIG_SOFTMMU) */