Commit 68016c627beb3df8ce69225b64ed6433efcc967d
1 parent
9d893301
SIGSEGV signals for ARM and SPARC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1272 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
65 additions
and
8 deletions
cpu-exec.c
| @@ -205,9 +205,7 @@ int cpu_exec(CPUState *env1) | @@ -205,9 +205,7 @@ int cpu_exec(CPUState *env1) | ||
| 205 | do_interrupt(env); | 205 | do_interrupt(env); |
| 206 | #elif defined(TARGET_SPARC) | 206 | #elif defined(TARGET_SPARC) |
| 207 | do_interrupt(env->exception_index, | 207 | do_interrupt(env->exception_index, |
| 208 | - 0, | ||
| 209 | - env->error_code, | ||
| 210 | - env->exception_next_pc, 0); | 208 | + env->error_code); |
| 211 | #endif | 209 | #endif |
| 212 | } | 210 | } |
| 213 | env->exception_index = -1; | 211 | env->exception_index = -1; |
| @@ -263,7 +261,7 @@ int cpu_exec(CPUState *env1) | @@ -263,7 +261,7 @@ int cpu_exec(CPUState *env1) | ||
| 263 | } | 261 | } |
| 264 | #elif defined(TARGET_SPARC) | 262 | #elif defined(TARGET_SPARC) |
| 265 | if (interrupt_request & CPU_INTERRUPT_HARD) { | 263 | if (interrupt_request & CPU_INTERRUPT_HARD) { |
| 266 | - do_interrupt(env->interrupt_index, 0, 0, 0, 0); | 264 | + do_interrupt(env->interrupt_index, 0); |
| 267 | env->interrupt_request &= ~CPU_INTERRUPT_HARD; | 265 | env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
| 268 | } else if (interrupt_request & CPU_INTERRUPT_TIMER) { | 266 | } else if (interrupt_request & CPU_INTERRUPT_TIMER) { |
| 269 | //do_interrupt(0, 0, 0, 0, 0); | 267 | //do_interrupt(0, 0, 0, 0, 0); |
| @@ -731,22 +729,72 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | @@ -731,22 +729,72 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | ||
| 731 | int is_write, sigset_t *old_set, | 729 | int is_write, sigset_t *old_set, |
| 732 | void *puc) | 730 | void *puc) |
| 733 | { | 731 | { |
| 732 | + TranslationBlock *tb; | ||
| 733 | + int ret; | ||
| 734 | + | ||
| 735 | + if (cpu_single_env) | ||
| 736 | + env = cpu_single_env; /* XXX: find a correct solution for multithread */ | ||
| 737 | +#if defined(DEBUG_SIGNAL) | ||
| 738 | + printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", | ||
| 739 | + pc, address, is_write, *(unsigned long *)old_set); | ||
| 740 | +#endif | ||
| 734 | /* XXX: locking issue */ | 741 | /* XXX: locking issue */ |
| 735 | if (is_write && page_unprotect(address, pc, puc)) { | 742 | if (is_write && page_unprotect(address, pc, puc)) { |
| 736 | return 1; | 743 | return 1; |
| 737 | } | 744 | } |
| 738 | - return 0; | 745 | + /* see if it is an MMU fault */ |
| 746 | + ret = cpu_arm_handle_mmu_fault(env, address, is_write, 1, 0); | ||
| 747 | + if (ret < 0) | ||
| 748 | + return 0; /* not an MMU fault */ | ||
| 749 | + if (ret == 0) | ||
| 750 | + return 1; /* the MMU fault was handled without causing real CPU fault */ | ||
| 751 | + /* now we have a real cpu fault */ | ||
| 752 | + tb = tb_find_pc(pc); | ||
| 753 | + if (tb) { | ||
| 754 | + /* the PC is inside the translated code. It means that we have | ||
| 755 | + a virtual CPU fault */ | ||
| 756 | + cpu_restore_state(tb, env, pc, puc); | ||
| 757 | + } | ||
| 758 | + /* we restore the process signal mask as the sigreturn should | ||
| 759 | + do it (XXX: use sigsetjmp) */ | ||
| 760 | + sigprocmask(SIG_SETMASK, old_set, NULL); | ||
| 761 | + cpu_loop_exit(); | ||
| 739 | } | 762 | } |
| 740 | #elif defined(TARGET_SPARC) | 763 | #elif defined(TARGET_SPARC) |
| 741 | static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | 764 | static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
| 742 | int is_write, sigset_t *old_set, | 765 | int is_write, sigset_t *old_set, |
| 743 | void *puc) | 766 | void *puc) |
| 744 | { | 767 | { |
| 768 | + TranslationBlock *tb; | ||
| 769 | + int ret; | ||
| 770 | + | ||
| 771 | + if (cpu_single_env) | ||
| 772 | + env = cpu_single_env; /* XXX: find a correct solution for multithread */ | ||
| 773 | +#if defined(DEBUG_SIGNAL) | ||
| 774 | + printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", | ||
| 775 | + pc, address, is_write, *(unsigned long *)old_set); | ||
| 776 | +#endif | ||
| 745 | /* XXX: locking issue */ | 777 | /* XXX: locking issue */ |
| 746 | if (is_write && page_unprotect(address, pc, puc)) { | 778 | if (is_write && page_unprotect(address, pc, puc)) { |
| 747 | return 1; | 779 | return 1; |
| 748 | } | 780 | } |
| 749 | - return 0; | 781 | + /* see if it is an MMU fault */ |
| 782 | + ret = cpu_sparc_handle_mmu_fault(env, address, is_write, 1, 0); | ||
| 783 | + if (ret < 0) | ||
| 784 | + return 0; /* not an MMU fault */ | ||
| 785 | + if (ret == 0) | ||
| 786 | + return 1; /* the MMU fault was handled without causing real CPU fault */ | ||
| 787 | + /* now we have a real cpu fault */ | ||
| 788 | + tb = tb_find_pc(pc); | ||
| 789 | + if (tb) { | ||
| 790 | + /* the PC is inside the translated code. It means that we have | ||
| 791 | + a virtual CPU fault */ | ||
| 792 | + cpu_restore_state(tb, env, pc, puc); | ||
| 793 | + } | ||
| 794 | + /* we restore the process signal mask as the sigreturn should | ||
| 795 | + do it (XXX: use sigsetjmp) */ | ||
| 796 | + sigprocmask(SIG_SETMASK, old_set, NULL); | ||
| 797 | + cpu_loop_exit(); | ||
| 750 | } | 798 | } |
| 751 | #elif defined (TARGET_PPC) | 799 | #elif defined (TARGET_PPC) |
| 752 | static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | 800 | static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
| @@ -756,10 +804,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | @@ -756,10 +804,8 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | ||
| 756 | TranslationBlock *tb; | 804 | TranslationBlock *tb; |
| 757 | int ret; | 805 | int ret; |
| 758 | 806 | ||
| 759 | -#if 1 | ||
| 760 | if (cpu_single_env) | 807 | if (cpu_single_env) |
| 761 | env = cpu_single_env; /* XXX: find a correct solution for multithread */ | 808 | env = cpu_single_env; /* XXX: find a correct solution for multithread */ |
| 762 | -#endif | ||
| 763 | #if defined(DEBUG_SIGNAL) | 809 | #if defined(DEBUG_SIGNAL) |
| 764 | printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", | 810 | printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", |
| 765 | pc, address, is_write, *(unsigned long *)old_set); | 811 | pc, address, is_write, *(unsigned long *)old_set); |
linux-user/main.c
| @@ -368,6 +368,17 @@ void cpu_loop(CPUARMState *env) | @@ -368,6 +368,17 @@ void cpu_loop(CPUARMState *env) | ||
| 368 | case EXCP_INTERRUPT: | 368 | case EXCP_INTERRUPT: |
| 369 | /* just indicate that signals should be handled asap */ | 369 | /* just indicate that signals should be handled asap */ |
| 370 | break; | 370 | break; |
| 371 | + case EXCP_PREFETCH_ABORT: | ||
| 372 | + case EXCP_DATA_ABORT: | ||
| 373 | + { | ||
| 374 | + info.si_signo = SIGSEGV; | ||
| 375 | + info.si_errno = 0; | ||
| 376 | + /* XXX: check env->error_code */ | ||
| 377 | + info.si_code = TARGET_SEGV_MAPERR; | ||
| 378 | + info._sifields._sigfault._addr = env->cp15_6; | ||
| 379 | + queue_signal(info.si_signo, &info); | ||
| 380 | + } | ||
| 381 | + break; | ||
| 371 | default: | 382 | default: |
| 372 | error: | 383 | error: |
| 373 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | 384 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |