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 | 205 | do_interrupt(env); |
| 206 | 206 | #elif defined(TARGET_SPARC) |
| 207 | 207 | do_interrupt(env->exception_index, |
| 208 | - 0, | |
| 209 | - env->error_code, | |
| 210 | - env->exception_next_pc, 0); | |
| 208 | + env->error_code); | |
| 211 | 209 | #endif |
| 212 | 210 | } |
| 213 | 211 | env->exception_index = -1; |
| ... | ... | @@ -263,7 +261,7 @@ int cpu_exec(CPUState *env1) |
| 263 | 261 | } |
| 264 | 262 | #elif defined(TARGET_SPARC) |
| 265 | 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 | 265 | env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
| 268 | 266 | } else if (interrupt_request & CPU_INTERRUPT_TIMER) { |
| 269 | 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 | 729 | int is_write, sigset_t *old_set, |
| 732 | 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 | 741 | /* XXX: locking issue */ |
| 735 | 742 | if (is_write && page_unprotect(address, pc, puc)) { |
| 736 | 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 | 763 | #elif defined(TARGET_SPARC) |
| 741 | 764 | static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
| 742 | 765 | int is_write, sigset_t *old_set, |
| 743 | 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 | 777 | /* XXX: locking issue */ |
| 746 | 778 | if (is_write && page_unprotect(address, pc, puc)) { |
| 747 | 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 | 799 | #elif defined (TARGET_PPC) |
| 752 | 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 | 804 | TranslationBlock *tb; |
| 757 | 805 | int ret; |
| 758 | 806 | |
| 759 | -#if 1 | |
| 760 | 807 | if (cpu_single_env) |
| 761 | 808 | env = cpu_single_env; /* XXX: find a correct solution for multithread */ |
| 762 | -#endif | |
| 763 | 809 | #if defined(DEBUG_SIGNAL) |
| 764 | 810 | printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", |
| 765 | 811 | pc, address, is_write, *(unsigned long *)old_set); | ... | ... |
linux-user/main.c
| ... | ... | @@ -368,6 +368,17 @@ void cpu_loop(CPUARMState *env) |
| 368 | 368 | case EXCP_INTERRUPT: |
| 369 | 369 | /* just indicate that signals should be handled asap */ |
| 370 | 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 | 382 | default: |
| 372 | 383 | error: |
| 373 | 384 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | ... | ... |