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 | } | ... | ... |