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