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 | 1617 | env->gregs[0] = ret; |
| 1618 | 1618 | env->pc += 2; |
| 1619 | 1619 | break; |
| 1620 | + case EXCP_INTERRUPT: | |
| 1621 | + /* just indicate that signals should be handled asap */ | |
| 1622 | + break; | |
| 1620 | 1623 | case EXCP_DEBUG: |
| 1621 | 1624 | { |
| 1622 | 1625 | int sig; |
| ... | ... | @@ -1631,6 +1634,15 @@ void cpu_loop (CPUState *env) |
| 1631 | 1634 | } |
| 1632 | 1635 | } |
| 1633 | 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 | 1646 | default: |
| 1635 | 1647 | printf ("Unhandled trap: 0x%x\n", trapnr); |
| 1636 | 1648 | cpu_dump_state(env, stderr, fprintf, 0); | ... | ... |
linux-user/sh4/target_signal.h
linux-user/signal.c
| ... | ... | @@ -562,6 +562,12 @@ static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, |
| 562 | 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 | 571 | #if defined(TARGET_I386) && TARGET_ABI_BITS == 32 |
| 566 | 572 | |
| 567 | 573 | /* from the Linux kernel */ |
| ... | ... | @@ -745,11 +751,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka, |
| 745 | 751 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
| 746 | 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 | 755 | &frame->sig); |
| 754 | 756 | if (err) |
| 755 | 757 | goto give_sigsegv; |
| ... | ... | @@ -819,11 +821,7 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka, |
| 819 | 821 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
| 820 | 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 | 825 | &frame->sig); |
| 828 | 826 | addr = frame_addr + offsetof(struct rt_sigframe, info); |
| 829 | 827 | err |= __put_user(addr, &frame->pinfo); |
| ... | ... | @@ -2406,6 +2404,309 @@ long do_rt_sigreturn(CPUState *env) |
| 2406 | 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 | 2710 | #else |
| 2410 | 2711 | |
| 2411 | 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 | 40 | int mmu_idx, int is_softmmu) |
| 41 | 41 | { |
| 42 | 42 | env->tea = address; |
| 43 | + env->exception_index = 0; | |
| 43 | 44 | switch (rw) { |
| 44 | 45 | case 0: |
| 46 | + env->tea = address; | |
| 45 | 47 | env->exception_index = 0x0a0; |
| 46 | 48 | break; |
| 47 | 49 | case 1: |
| 50 | + env->tea = address; | |
| 48 | 51 | env->exception_index = 0x0c0; |
| 49 | 52 | break; |
| 50 | - case 2: | |
| 51 | - env->exception_index = 0x0a0; | |
| 52 | - break; | |
| 53 | 53 | } |
| 54 | 54 | return 1; |
| 55 | 55 | } | ... | ... |