Commit c3b5bc8ab325bd3aee46ea5c0884c9e6f1636ccb
1 parent
03aa1976
SH4: Signal handling for the user space emulator, by Magnus Damm.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3764 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
331 additions
and
13 deletions
linux-user/main.c
@@ -1617,6 +1617,9 @@ void cpu_loop (CPUState *env) | @@ -1617,6 +1617,9 @@ void cpu_loop (CPUState *env) | ||
1617 | env->gregs[0] = ret; | 1617 | env->gregs[0] = ret; |
1618 | env->pc += 2; | 1618 | env->pc += 2; |
1619 | break; | 1619 | break; |
1620 | + case EXCP_INTERRUPT: | ||
1621 | + /* just indicate that signals should be handled asap */ | ||
1622 | + break; | ||
1620 | case EXCP_DEBUG: | 1623 | case EXCP_DEBUG: |
1621 | { | 1624 | { |
1622 | int sig; | 1625 | int sig; |
@@ -1631,6 +1634,15 @@ void cpu_loop (CPUState *env) | @@ -1631,6 +1634,15 @@ void cpu_loop (CPUState *env) | ||
1631 | } | 1634 | } |
1632 | } | 1635 | } |
1633 | break; | 1636 | break; |
1637 | + case 0xa0: | ||
1638 | + case 0xc0: | ||
1639 | + info.si_signo = SIGSEGV; | ||
1640 | + info.si_errno = 0; | ||
1641 | + info.si_code = TARGET_SEGV_MAPERR; | ||
1642 | + info._sifields._sigfault._addr = env->tea; | ||
1643 | + queue_signal(info.si_signo, &info); | ||
1644 | + break; | ||
1645 | + | ||
1634 | default: | 1646 | default: |
1635 | printf ("Unhandled trap: 0x%x\n", trapnr); | 1647 | printf ("Unhandled trap: 0x%x\n", trapnr); |
1636 | cpu_dump_state(env, stderr, fprintf, 0); | 1648 | cpu_dump_state(env, stderr, fprintf, 0); |
linux-user/sh4/target_signal.h
@@ -21,4 +21,9 @@ typedef struct target_sigaltstack { | @@ -21,4 +21,9 @@ typedef struct target_sigaltstack { | ||
21 | #define TARGET_MINSIGSTKSZ 2048 | 21 | #define TARGET_MINSIGSTKSZ 2048 |
22 | #define TARGET_SIGSTKSZ 8192 | 22 | #define TARGET_SIGSTKSZ 8192 |
23 | 23 | ||
24 | +static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state) | ||
25 | +{ | ||
26 | + return state->gregs[15]; | ||
27 | +} | ||
28 | + | ||
24 | #endif /* TARGET_SIGNAL_H */ | 29 | #endif /* TARGET_SIGNAL_H */ |
linux-user/signal.c
@@ -562,6 +562,12 @@ static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, | @@ -562,6 +562,12 @@ static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, | ||
562 | return 0; | 562 | return 0; |
563 | } | 563 | } |
564 | 564 | ||
565 | +static inline int current_exec_domain_sig(int sig) | ||
566 | +{ | ||
567 | + return /* current->exec_domain && current->exec_domain->signal_invmap | ||
568 | + && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig; | ||
569 | +} | ||
570 | + | ||
565 | #if defined(TARGET_I386) && TARGET_ABI_BITS == 32 | 571 | #if defined(TARGET_I386) && TARGET_ABI_BITS == 32 |
566 | 572 | ||
567 | /* from the Linux kernel */ | 573 | /* from the Linux kernel */ |
@@ -745,11 +751,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, | @@ -745,11 +751,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, | ||
745 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) | 751 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
746 | goto give_sigsegv; | 752 | goto give_sigsegv; |
747 | 753 | ||
748 | - err |= __put_user((/*current->exec_domain | ||
749 | - && current->exec_domain->signal_invmap | ||
750 | - && sig < 32 | ||
751 | - ? current->exec_domain->signal_invmap[sig] | ||
752 | - : */ sig), | 754 | + err |= __put_user(current_exec_domain_sig(sig), |
753 | &frame->sig); | 755 | &frame->sig); |
754 | if (err) | 756 | if (err) |
755 | goto give_sigsegv; | 757 | goto give_sigsegv; |
@@ -819,11 +821,7 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, | @@ -819,11 +821,7 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, | ||
819 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) | 821 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
820 | goto give_sigsegv; | 822 | goto give_sigsegv; |
821 | 823 | ||
822 | - err |= __put_user((/*current->exec_domain | ||
823 | - && current->exec_domain->signal_invmap | ||
824 | - && sig < 32 | ||
825 | - ? current->exec_domain->signal_invmap[sig] | ||
826 | - : */sig), | 824 | + err |= __put_user(current_exec_domain_sig(sig), |
827 | &frame->sig); | 825 | &frame->sig); |
828 | addr = frame_addr + offsetof(struct rt_sigframe, info); | 826 | addr = frame_addr + offsetof(struct rt_sigframe, info); |
829 | err |= __put_user(addr, &frame->pinfo); | 827 | err |= __put_user(addr, &frame->pinfo); |
@@ -2406,6 +2404,309 @@ long do_rt_sigreturn(CPUState *env) | @@ -2406,6 +2404,309 @@ long do_rt_sigreturn(CPUState *env) | ||
2406 | return -TARGET_ENOSYS; | 2404 | return -TARGET_ENOSYS; |
2407 | } | 2405 | } |
2408 | 2406 | ||
2407 | +#elif defined(TARGET_SH4) | ||
2408 | + | ||
2409 | +/* | ||
2410 | + * code and data structures from linux kernel: | ||
2411 | + * include/asm-sh/sigcontext.h | ||
2412 | + * arch/sh/kernel/signal.c | ||
2413 | + */ | ||
2414 | + | ||
2415 | +struct target_sigcontext { | ||
2416 | + target_ulong oldmask; | ||
2417 | + | ||
2418 | + /* CPU registers */ | ||
2419 | + target_ulong sc_gregs[16]; | ||
2420 | + target_ulong sc_pc; | ||
2421 | + target_ulong sc_pr; | ||
2422 | + target_ulong sc_sr; | ||
2423 | + target_ulong sc_gbr; | ||
2424 | + target_ulong sc_mach; | ||
2425 | + target_ulong sc_macl; | ||
2426 | + | ||
2427 | + /* FPU registers */ | ||
2428 | + target_ulong sc_fpregs[16]; | ||
2429 | + target_ulong sc_xfpregs[16]; | ||
2430 | + unsigned int sc_fpscr; | ||
2431 | + unsigned int sc_fpul; | ||
2432 | + unsigned int sc_ownedfp; | ||
2433 | +}; | ||
2434 | + | ||
2435 | +struct target_sigframe | ||
2436 | +{ | ||
2437 | + struct target_sigcontext sc; | ||
2438 | + target_ulong extramask[TARGET_NSIG_WORDS-1]; | ||
2439 | + uint16_t retcode[3]; | ||
2440 | +}; | ||
2441 | + | ||
2442 | + | ||
2443 | +struct target_ucontext { | ||
2444 | + target_ulong uc_flags; | ||
2445 | + struct target_ucontext *uc_link; | ||
2446 | + target_stack_t uc_stack; | ||
2447 | + struct target_sigcontext uc_mcontext; | ||
2448 | + target_sigset_t uc_sigmask; /* mask last for extensibility */ | ||
2449 | +}; | ||
2450 | + | ||
2451 | +struct target_rt_sigframe | ||
2452 | +{ | ||
2453 | + struct target_siginfo info; | ||
2454 | + struct target_ucontext uc; | ||
2455 | + uint16_t retcode[3]; | ||
2456 | +}; | ||
2457 | + | ||
2458 | + | ||
2459 | +#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ | ||
2460 | +#define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */ | ||
2461 | + | ||
2462 | +static abi_ulong get_sigframe(struct emulated_sigaction *ka, | ||
2463 | + unsigned long sp, size_t frame_size) | ||
2464 | +{ | ||
2465 | + if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { | ||
2466 | + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; | ||
2467 | + } | ||
2468 | + | ||
2469 | + return (sp - frame_size) & -8ul; | ||
2470 | +} | ||
2471 | + | ||
2472 | +static int setup_sigcontext(struct target_sigcontext *sc, | ||
2473 | + CPUState *regs, unsigned long mask) | ||
2474 | +{ | ||
2475 | + int err = 0; | ||
2476 | + | ||
2477 | +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) | ||
2478 | + COPY(gregs[0]); COPY(gregs[1]); | ||
2479 | + COPY(gregs[2]); COPY(gregs[3]); | ||
2480 | + COPY(gregs[4]); COPY(gregs[5]); | ||
2481 | + COPY(gregs[6]); COPY(gregs[7]); | ||
2482 | + COPY(gregs[8]); COPY(gregs[9]); | ||
2483 | + COPY(gregs[10]); COPY(gregs[11]); | ||
2484 | + COPY(gregs[12]); COPY(gregs[13]); | ||
2485 | + COPY(gregs[14]); COPY(gregs[15]); | ||
2486 | + COPY(gbr); COPY(mach); | ||
2487 | + COPY(macl); COPY(pr); | ||
2488 | + COPY(sr); COPY(pc); | ||
2489 | +#undef COPY | ||
2490 | + | ||
2491 | + /* todo: save FPU registers here */ | ||
2492 | + | ||
2493 | + /* non-iBCS2 extensions.. */ | ||
2494 | + err |= __put_user(mask, &sc->oldmask); | ||
2495 | + | ||
2496 | + return err; | ||
2497 | +} | ||
2498 | + | ||
2499 | +static int restore_sigcontext(struct CPUState *regs, | ||
2500 | + struct target_sigcontext *sc) | ||
2501 | +{ | ||
2502 | + unsigned int err = 0; | ||
2503 | + | ||
2504 | +#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) | ||
2505 | + COPY(gregs[1]); | ||
2506 | + COPY(gregs[2]); COPY(gregs[3]); | ||
2507 | + COPY(gregs[4]); COPY(gregs[5]); | ||
2508 | + COPY(gregs[6]); COPY(gregs[7]); | ||
2509 | + COPY(gregs[8]); COPY(gregs[9]); | ||
2510 | + COPY(gregs[10]); COPY(gregs[11]); | ||
2511 | + COPY(gregs[12]); COPY(gregs[13]); | ||
2512 | + COPY(gregs[14]); COPY(gregs[15]); | ||
2513 | + COPY(gbr); COPY(mach); | ||
2514 | + COPY(macl); COPY(pr); | ||
2515 | + COPY(sr); COPY(pc); | ||
2516 | +#undef COPY | ||
2517 | + | ||
2518 | + /* todo: restore FPU registers here */ | ||
2519 | + | ||
2520 | + regs->tra = -1; /* disable syscall checks */ | ||
2521 | + return err; | ||
2522 | +} | ||
2523 | + | ||
2524 | +static void setup_frame(int sig, struct emulated_sigaction *ka, | ||
2525 | + target_sigset_t *set, CPUState *regs) | ||
2526 | +{ | ||
2527 | + struct target_sigframe *frame; | ||
2528 | + abi_ulong frame_addr; | ||
2529 | + int i; | ||
2530 | + int err = 0; | ||
2531 | + int signal; | ||
2532 | + | ||
2533 | + frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); | ||
2534 | + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) | ||
2535 | + goto give_sigsegv; | ||
2536 | + | ||
2537 | + signal = current_exec_domain_sig(sig); | ||
2538 | + | ||
2539 | + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | ||
2540 | + | ||
2541 | + for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { | ||
2542 | + err |= __put_user(set->sig[i + 1], &frame->extramask[i]); | ||
2543 | + } | ||
2544 | + | ||
2545 | + /* Set up to return from userspace. If provided, use a stub | ||
2546 | + already in userspace. */ | ||
2547 | + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { | ||
2548 | + regs->pr = (unsigned long) ka->sa.sa_restorer; | ||
2549 | + } else { | ||
2550 | + /* Generate return code (system call to sigreturn) */ | ||
2551 | + err |= __put_user(MOVW(2), &frame->retcode[0]); | ||
2552 | + err |= __put_user(TRAP_NOARG, &frame->retcode[1]); | ||
2553 | + err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]); | ||
2554 | + regs->pr = (unsigned long) frame->retcode; | ||
2555 | + } | ||
2556 | + | ||
2557 | + if (err) | ||
2558 | + goto give_sigsegv; | ||
2559 | + | ||
2560 | + /* Set up registers for signal handler */ | ||
2561 | + regs->gregs[15] = (unsigned long) frame; | ||
2562 | + regs->gregs[4] = signal; /* Arg for signal handler */ | ||
2563 | + regs->gregs[5] = 0; | ||
2564 | + regs->gregs[6] = (unsigned long) &frame->sc; | ||
2565 | + regs->pc = (unsigned long) ka->sa._sa_handler; | ||
2566 | + | ||
2567 | + unlock_user_struct(frame, frame_addr, 1); | ||
2568 | + return; | ||
2569 | + | ||
2570 | +give_sigsegv: | ||
2571 | + unlock_user_struct(frame, frame_addr, 1); | ||
2572 | + force_sig(SIGSEGV); | ||
2573 | +} | ||
2574 | + | ||
2575 | +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, | ||
2576 | + target_siginfo_t *info, | ||
2577 | + target_sigset_t *set, CPUState *regs) | ||
2578 | +{ | ||
2579 | + struct target_rt_sigframe *frame; | ||
2580 | + abi_ulong frame_addr; | ||
2581 | + int i; | ||
2582 | + int err = 0; | ||
2583 | + int signal; | ||
2584 | + | ||
2585 | + frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); | ||
2586 | + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) | ||
2587 | + goto give_sigsegv; | ||
2588 | + | ||
2589 | + signal = current_exec_domain_sig(sig); | ||
2590 | + | ||
2591 | + err |= copy_siginfo_to_user(&frame->info, info); | ||
2592 | + | ||
2593 | + /* Create the ucontext. */ | ||
2594 | + err |= __put_user(0, &frame->uc.uc_flags); | ||
2595 | + err |= __put_user(0, (unsigned long *)&frame->uc.uc_link); | ||
2596 | + err |= __put_user((void *)target_sigaltstack_used.ss_sp, | ||
2597 | + &frame->uc.uc_stack.ss_sp); | ||
2598 | + err |= __put_user(sas_ss_flags(regs->gregs[15]), | ||
2599 | + &frame->uc.uc_stack.ss_flags); | ||
2600 | + err |= __put_user(target_sigaltstack_used.ss_size, | ||
2601 | + &frame->uc.uc_stack.ss_size); | ||
2602 | + err |= setup_sigcontext(&frame->uc.uc_mcontext, | ||
2603 | + regs, set->sig[0]); | ||
2604 | + for(i = 0; i < TARGET_NSIG_WORDS; i++) { | ||
2605 | + err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]); | ||
2606 | + } | ||
2607 | + | ||
2608 | + /* Set up to return from userspace. If provided, use a stub | ||
2609 | + already in userspace. */ | ||
2610 | + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { | ||
2611 | + regs->pr = (unsigned long) ka->sa.sa_restorer; | ||
2612 | + } else { | ||
2613 | + /* Generate return code (system call to sigreturn) */ | ||
2614 | + err |= __put_user(MOVW(2), &frame->retcode[0]); | ||
2615 | + err |= __put_user(TRAP_NOARG, &frame->retcode[1]); | ||
2616 | + err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]); | ||
2617 | + regs->pr = (unsigned long) frame->retcode; | ||
2618 | + } | ||
2619 | + | ||
2620 | + if (err) | ||
2621 | + goto give_sigsegv; | ||
2622 | + | ||
2623 | + /* Set up registers for signal handler */ | ||
2624 | + regs->gregs[15] = (unsigned long) frame; | ||
2625 | + regs->gregs[4] = signal; /* Arg for signal handler */ | ||
2626 | + regs->gregs[5] = (unsigned long) &frame->info; | ||
2627 | + regs->gregs[6] = (unsigned long) &frame->uc; | ||
2628 | + regs->pc = (unsigned long) ka->sa._sa_handler; | ||
2629 | + | ||
2630 | + unlock_user_struct(frame, frame_addr, 1); | ||
2631 | + return; | ||
2632 | + | ||
2633 | +give_sigsegv: | ||
2634 | + unlock_user_struct(frame, frame_addr, 1); | ||
2635 | + force_sig(SIGSEGV); | ||
2636 | +} | ||
2637 | + | ||
2638 | +long do_sigreturn(CPUState *regs) | ||
2639 | +{ | ||
2640 | + struct target_sigframe *frame; | ||
2641 | + abi_ulong frame_addr; | ||
2642 | + sigset_t blocked; | ||
2643 | + target_sigset_t target_set; | ||
2644 | + int i; | ||
2645 | + int err = 0; | ||
2646 | + | ||
2647 | +#if defined(DEBUG_SIGNAL) | ||
2648 | + fprintf(stderr, "do_sigreturn\n"); | ||
2649 | +#endif | ||
2650 | + frame_addr = regs->gregs[15]; | ||
2651 | + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) | ||
2652 | + goto badframe; | ||
2653 | + | ||
2654 | + err |= __get_user(target_set.sig[0], &frame->sc.oldmask); | ||
2655 | + for(i = 1; i < TARGET_NSIG_WORDS; i++) { | ||
2656 | + err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1])); | ||
2657 | + } | ||
2658 | + | ||
2659 | + if (err) | ||
2660 | + goto badframe; | ||
2661 | + | ||
2662 | + target_to_host_sigset_internal(&blocked, &target_set); | ||
2663 | + sigprocmask(SIG_SETMASK, &blocked, NULL); | ||
2664 | + | ||
2665 | + if (restore_sigcontext(regs, &frame->sc)) | ||
2666 | + goto badframe; | ||
2667 | + | ||
2668 | + unlock_user_struct(frame, frame_addr, 0); | ||
2669 | + return regs->gregs[0]; | ||
2670 | + | ||
2671 | +badframe: | ||
2672 | + unlock_user_struct(frame, frame_addr, 0); | ||
2673 | + force_sig(TARGET_SIGSEGV); | ||
2674 | + return 0; | ||
2675 | +} | ||
2676 | + | ||
2677 | +long do_rt_sigreturn(CPUState *regs) | ||
2678 | +{ | ||
2679 | + struct target_rt_sigframe *frame; | ||
2680 | + abi_ulong frame_addr; | ||
2681 | + sigset_t blocked; | ||
2682 | + | ||
2683 | +#if defined(DEBUG_SIGNAL) | ||
2684 | + fprintf(stderr, "do_rt_sigreturn\n"); | ||
2685 | +#endif | ||
2686 | + frame_addr = regs->gregs[15]; | ||
2687 | + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) | ||
2688 | + goto badframe; | ||
2689 | + | ||
2690 | + target_to_host_sigset(&blocked, &frame->uc.uc_sigmask); | ||
2691 | + sigprocmask(SIG_SETMASK, &blocked, NULL); | ||
2692 | + | ||
2693 | + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | ||
2694 | + goto badframe; | ||
2695 | + | ||
2696 | + if (do_sigaltstack(frame_addr + | ||
2697 | + offsetof(struct target_rt_sigframe, uc.uc_stack), | ||
2698 | + 0, get_sp_from_cpustate(regs)) == -EFAULT) | ||
2699 | + goto badframe; | ||
2700 | + | ||
2701 | + unlock_user_struct(frame, frame_addr, 0); | ||
2702 | + return regs->gregs[0]; | ||
2703 | + | ||
2704 | +badframe: | ||
2705 | + unlock_user_struct(frame, frame_addr, 0); | ||
2706 | + force_sig(TARGET_SIGSEGV); | ||
2707 | + return 0; | ||
2708 | +} | ||
2709 | + | ||
2409 | #else | 2710 | #else |
2410 | 2711 | ||
2411 | static void setup_frame(int sig, struct emulated_sigaction *ka, | 2712 | static void setup_frame(int sig, struct emulated_sigaction *ka, |
target-sh4/helper.c
@@ -40,16 +40,16 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, | @@ -40,16 +40,16 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, | ||
40 | int mmu_idx, int is_softmmu) | 40 | int mmu_idx, int is_softmmu) |
41 | { | 41 | { |
42 | env->tea = address; | 42 | env->tea = address; |
43 | + env->exception_index = 0; | ||
43 | switch (rw) { | 44 | switch (rw) { |
44 | case 0: | 45 | case 0: |
46 | + env->tea = address; | ||
45 | env->exception_index = 0x0a0; | 47 | env->exception_index = 0x0a0; |
46 | break; | 48 | break; |
47 | case 1: | 49 | case 1: |
50 | + env->tea = address; | ||
48 | env->exception_index = 0x0c0; | 51 | env->exception_index = 0x0c0; |
49 | break; | 52 | break; |
50 | - case 2: | ||
51 | - env->exception_index = 0x0a0; | ||
52 | - break; | ||
53 | } | 53 | } |
54 | return 1; | 54 | return 1; |
55 | } | 55 | } |