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", | ... | ... |