Commit c3b5bc8ab325bd3aee46ea5c0884c9e6f1636ccb

Authored by ths
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
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
... ... @@ -21,4 +21,9 @@ typedef struct target_sigaltstack {
21 21 #define TARGET_MINSIGSTKSZ 2048
22 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 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 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 }
... ...