qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] sh4: add signal handling support for user space emulator
@ 2007-11-21  8:16 Magnus Damm
  2007-11-21  8:40 ` Paul Mundt
  0 siblings, 1 reply; 3+ messages in thread
From: Magnus Damm @ 2007-11-21  8:16 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 109 bytes --]

Hi everyone,

This adds SH support to the user space signal emulation code. Please apply.

Thanks,

/ magnus

[-- Attachment #2: qemu-cvs-20071121c-sh4-signal.patch --]
[-- Type: application/octet-stream, Size: 13185 bytes --]

--- 0001/linux-user/main.c
+++ work/linux-user/main.c	2007-11-21 16:26:16.000000000 +0900
@@ -1617,6 +1617,9 @@ void cpu_loop (CPUState *env)
             env->gregs[0] = ret;
             env->pc += 2;
             break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
         case EXCP_DEBUG:
             {
                 int sig;
@@ -1631,6 +1634,15 @@ void cpu_loop (CPUState *env)
                   }
             }
             break;
+	case 0xa0:
+	case 0xc0:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SEGV_MAPERR;
+            info._sifields._sigfault._addr = env->tea;
+            queue_signal(info.si_signo, &info);
+	    break;
+
         default:
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
--- 0001/linux-user/sh4/target_signal.h
+++ work/linux-user/sh4/target_signal.h	2007-11-21 16:26:16.000000000 +0900
@@ -21,4 +21,9 @@ typedef struct target_sigaltstack {
 #define TARGET_MINSIGSTKSZ    2048
 #define TARGET_SIGSTKSZ       8192
 
+static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state)
+{
+    return state->gregs[15];
+}
+
 #endif /* TARGET_SIGNAL_H */
--- 0001/linux-user/signal.c
+++ work/linux-user/signal.c	2007-11-21 16:36:58.000000000 +0900
@@ -562,6 +562,12 @@ static inline int copy_siginfo_to_user(t
     return 0;
 }
 
+static inline int current_exec_domain_sig(int sig)
+{
+    return /* current->exec_domain && current->exec_domain->signal_invmap
+	      && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
+}
+
 #if defined(TARGET_I386) && TARGET_ABI_BITS == 32
 
 /* from the Linux kernel */
@@ -745,11 +751,7 @@ static void setup_frame(int sig, struct 
 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
 		goto give_sigsegv;
 
-	err |= __put_user((/*current->exec_domain
-		           && current->exec_domain->signal_invmap
-		           && sig < 32
-		           ? current->exec_domain->signal_invmap[sig]
-		           : */ sig),
+	err |= __put_user(current_exec_domain_sig(sig),
 		          &frame->sig);
 	if (err)
 		goto give_sigsegv;
@@ -819,11 +821,7 @@ static void setup_rt_frame(int sig, stru
 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
 		goto give_sigsegv;
 
-	err |= __put_user((/*current->exec_domain
-		    	   && current->exec_domain->signal_invmap
-		    	   && sig < 32
-		    	   ? current->exec_domain->signal_invmap[sig]
-			   : */sig),
+	err |= __put_user(current_exec_domain_sig(sig),
 			  &frame->sig);
         addr = frame_addr + offsetof(struct rt_sigframe, info);
 	err |= __put_user(addr, &frame->pinfo);
@@ -2406,6 +2404,320 @@ long do_rt_sigreturn(CPUState *env)
     return -TARGET_ENOSYS;
 }
 
+#elif defined(TARGET_SH4)
+
+/*
+ * code and data structures from linux kernel:
+ * include/asm-sh/sigcontext.h
+ * arch/sh/kernel/signal.c
+ */
+
+struct target_sigcontext {
+    target_ulong  oldmask;
+
+    /* CPU registers */
+    target_ulong  sc_gregs[16];
+    target_ulong  sc_pc;
+    target_ulong  sc_pr;
+    target_ulong  sc_sr;
+    target_ulong  sc_gbr;
+    target_ulong  sc_mach;
+    target_ulong  sc_macl;
+
+    /* FPU registers */
+    target_ulong  sc_fpregs[16];
+    target_ulong  sc_xfpregs[16];
+    unsigned int sc_fpscr;
+    unsigned int sc_fpul;
+    unsigned int sc_ownedfp;
+};
+
+struct target_sigframe
+{
+    struct target_sigcontext sc;
+    target_ulong extramask[TARGET_NSIG_WORDS-1];
+    uint16_t retcode[8];
+};
+
+
+struct target_ucontext {
+    target_ulong uc_flags;
+    struct target_ucontext *uc_link;
+    target_stack_t uc_stack;
+    struct target_sigcontext uc_mcontext;
+    target_sigset_t uc_sigmask;	/* mask last for extensibility */
+};
+
+struct target_rt_sigframe
+{
+    struct target_siginfo info;
+    struct target_ucontext uc;
+    uint16_t retcode[8];
+};
+
+
+#define MOVW(n)  (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
+#define TRAP_NOARG 0xc310         /* Syscall w/no args (NR in R3) SH3/4 */
+#define OR_R0_R0 0x200b           /* or r0,r0 (insert to avoid hardware bug) */
+
+static abi_ulong get_sigframe(struct emulated_sigaction *ka,
+                         unsigned long sp, size_t frame_size)
+{
+    if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+    }
+
+    return (sp - frame_size) & -8ul;
+}
+
+static int setup_sigcontext(struct target_sigcontext *sc,
+			    CPUState *regs, unsigned long mask)
+{
+    int err = 0;
+
+#define COPY(x)         err |= __put_user(regs->x, &sc->sc_##x)
+    COPY(gregs[0]); COPY(gregs[1]);
+    COPY(gregs[2]); COPY(gregs[3]);
+    COPY(gregs[4]); COPY(gregs[5]);
+    COPY(gregs[6]); COPY(gregs[7]);
+    COPY(gregs[8]); COPY(gregs[9]);
+    COPY(gregs[10]); COPY(gregs[11]);
+    COPY(gregs[12]); COPY(gregs[13]);
+    COPY(gregs[14]); COPY(gregs[15]);
+    COPY(gbr); COPY(mach);
+    COPY(macl); COPY(pr);
+    COPY(sr); COPY(pc);
+#undef COPY
+
+    /* todo: save FPU registers here */
+
+    /* non-iBCS2 extensions.. */
+    err |= __put_user(mask, &sc->oldmask);
+
+    return err;
+}
+
+static int restore_sigcontext(struct CPUState *regs,
+			      struct target_sigcontext *sc)
+{
+    unsigned int err = 0;
+
+#define COPY(x)         err |= __get_user(regs->x, &sc->sc_##x)
+    COPY(gregs[1]);
+    COPY(gregs[2]); COPY(gregs[3]);
+    COPY(gregs[4]); COPY(gregs[5]);
+    COPY(gregs[6]); COPY(gregs[7]);
+    COPY(gregs[8]); COPY(gregs[9]);
+    COPY(gregs[10]); COPY(gregs[11]);
+    COPY(gregs[12]); COPY(gregs[13]);
+    COPY(gregs[14]); COPY(gregs[15]);
+    COPY(gbr); COPY(mach);
+    COPY(macl); COPY(pr);
+    COPY(sr); COPY(pc);
+#undef COPY
+
+    /* todo: restore FPU registers here */
+
+    regs->tra = -1;         /* disable syscall checks */
+    return err;
+}
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+			target_sigset_t *set, CPUState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+    int err = 0;
+    int signal;
+
+    frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+    for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
+        err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
+    }
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
+        regs->pr = (unsigned long) ka->sa.sa_restorer;
+    } else {
+        /* Generate return code (system call to sigreturn) */
+        err |= __put_user(MOVW(7), &frame->retcode[0]);
+        err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[2]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[3]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[4]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[5]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[6]);
+        err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[7]);
+        regs->pr = (unsigned long) frame->retcode;
+    }
+
+    if (err)
+        goto give_sigsegv;
+
+    /* Set up registers for signal handler */
+    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[4] = signal; /* Arg for signal handler */
+    regs->gregs[5] = 0;
+    regs->gregs[6] = (unsigned long) &frame->sc;
+    regs->pc = (unsigned long) ka->sa._sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *regs)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+    int err = 0;
+    int signal;
+
+    frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= copy_siginfo_to_user(&frame->info, info);
+
+    /* Create the ucontext.  */
+    err |= __put_user(0, &frame->uc.uc_flags);
+    err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
+    err |= __put_user((void *)target_sigaltstack_used.ss_sp,
+		      &frame->uc.uc_stack.ss_sp);
+    err |= __put_user(sas_ss_flags(regs->gregs[15]),
+		      &frame->uc.uc_stack.ss_flags);
+    err |= __put_user(target_sigaltstack_used.ss_size,
+		      &frame->uc.uc_stack.ss_size);
+    err |= setup_sigcontext(&frame->uc.uc_mcontext,
+			    regs, set->sig[0]);
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
+    }
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
+        regs->pr = (unsigned long) ka->sa.sa_restorer;
+    } else {
+        /* Generate return code (system call to sigreturn) */
+        err |= __put_user(MOVW(7), &frame->retcode[0]);
+        err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[2]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[3]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[4]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[5]);
+        err |= __put_user(OR_R0_R0, &frame->retcode[6]);
+        err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[7]);
+        regs->pr = (unsigned long) frame->retcode;
+    }
+
+    if (err)
+        goto give_sigsegv;
+
+    /* Set up registers for signal handler */
+    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[4] = signal; /* Arg for signal handler */
+    regs->gregs[5] = (unsigned long) &frame->info;
+    regs->gregs[6] = (unsigned long) &frame->uc;
+    regs->pc = (unsigned long) ka->sa._sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(SIGSEGV);
+}
+
+long do_sigreturn(CPUState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+    target_sigset_t target_set;
+    int i;
+    int err = 0;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigreturn\n");
+#endif
+    frame_addr = regs->gregs[15];
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+   	goto badframe;
+
+    err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
+    for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+        err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
+    }
+
+    if (err)
+        goto badframe;
+
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (restore_sigcontext(regs, &frame->sc))
+        goto badframe;
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return regs->gregs[0];
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+long do_rt_sigreturn(CPUState *regs)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_rt_sigreturn\n");
+#endif
+    frame_addr = regs->gregs[15];
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+   	goto badframe;
+
+    target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+        goto badframe;
+
+    if (do_sigaltstack(frame_addr +
+		       offsetof(struct target_rt_sigframe, uc.uc_stack),
+		       0, get_sp_from_cpustate(regs)) == -EFAULT)
+        goto badframe;
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return regs->gregs[0];
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
 #else
 
 static void setup_frame(int sig, struct emulated_sigaction *ka,
--- 0001/target-sh4/helper.c
+++ work/target-sh4/helper.c	2007-11-21 16:26:16.000000000 +0900
@@ -39,16 +39,16 @@ int cpu_sh4_handle_mmu_fault(CPUState * 
 			     int mmu_idx, int is_softmmu)
 {
     env->tea = address;
+    env->exception_index = 0;
     switch (rw) {
     case 0:
+	env->tea = address;
         env->exception_index = 0x0a0;
         break;
     case 1:
+	env->tea = address;
         env->exception_index = 0x0c0;
         break;
-    case 2:
-        env->exception_index = 0x0a0;
-        break;
     }
     return 1;
 }
--- 0001/translate-all.c
+++ work/translate-all.c	2007-11-21 16:26:16.000000000 +0900
@@ -298,6 +298,8 @@ int cpu_restore_state(TranslationBlock *
     env->hflags |= gen_opc_hflags[j];
 #elif defined(TARGET_ALPHA)
     env->pc = gen_opc_pc[j];
+#elif defined(TARGET_SH4)
+    env->pc = gen_opc_pc[j];
 #endif
     return 0;
 }

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] [PATCH] sh4: add signal handling support for user space emulator
  2007-11-21  8:16 [Qemu-devel] [PATCH] sh4: add signal handling support for user space emulator Magnus Damm
@ 2007-11-21  8:40 ` Paul Mundt
  2007-11-22  4:59   ` Magnus Damm
  0 siblings, 1 reply; 3+ messages in thread
From: Paul Mundt @ 2007-11-21  8:40 UTC (permalink / raw)
  To: qemu-devel

On Wed, Nov 21, 2007 at 05:16:55PM +0900, Magnus Damm wrote:
> +#define MOVW(n)  (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
> +#define TRAP_NOARG 0xc310         /* Syscall w/no args (NR in R3) SH3/4 */
> +#define OR_R0_R0 0x200b           /* or r0,r0 (insert to avoid hardware bug) */
This is legacy SH-4 errata, and does not pop up on any of the other
parts. These days all SH-4 parts return through the vsyscall page, where
we deal with this errata directly without having to push it in to the
return frame. While you might not want to deal with implementing the
vsyscall page, there's definitely no point in crapping up the return
frame with this chip errata in the general case.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] [PATCH] sh4: add signal handling support for user space emulator
  2007-11-21  8:40 ` Paul Mundt
@ 2007-11-22  4:59   ` Magnus Damm
  0 siblings, 0 replies; 3+ messages in thread
From: Magnus Damm @ 2007-11-22  4:59 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1019 bytes --]

On Nov 21, 2007 5:40 PM, Paul Mundt <lethal@linux-sh.org> wrote:
> On Wed, Nov 21, 2007 at 05:16:55PM +0900, Magnus Damm wrote:
> > +#define MOVW(n)  (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
> > +#define TRAP_NOARG 0xc310         /* Syscall w/no args (NR in R3) SH3/4 */
> > +#define OR_R0_R0 0x200b           /* or r0,r0 (insert to avoid hardware bug) */
> This is legacy SH-4 errata, and does not pop up on any of the other
> parts. These days all SH-4 parts return through the vsyscall page, where
> we deal with this errata directly without having to push it in to the
> return frame. While you might not want to deal with implementing the
> vsyscall page, there's definitely no point in crapping up the return
> frame with this chip errata in the general case.

Thanks for your feedback. vsyscall sounds nice and all, but I prefer
to do this in incremental steps. So let's start with this.

I've attached a new version of the patch where the OR instructions are
removed. Please apply.

Thanks,

/ magnus

[-- Attachment #2: qemu-cvs-20071122-sh4-signal.patch --]
[-- Type: application/octet-stream, Size: 12524 bytes --]

--- 0001/linux-user/main.c
+++ work/linux-user/main.c	2007-11-22 12:12:25.000000000 +0900
@@ -1617,6 +1617,9 @@ void cpu_loop (CPUState *env)
             env->gregs[0] = ret;
             env->pc += 2;
             break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
         case EXCP_DEBUG:
             {
                 int sig;
@@ -1631,6 +1634,15 @@ void cpu_loop (CPUState *env)
                   }
             }
             break;
+	case 0xa0:
+	case 0xc0:
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SEGV_MAPERR;
+            info._sifields._sigfault._addr = env->tea;
+            queue_signal(info.si_signo, &info);
+	    break;
+
         default:
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
--- 0001/linux-user/sh4/target_signal.h
+++ work/linux-user/sh4/target_signal.h	2007-11-22 12:12:25.000000000 +0900
@@ -21,4 +21,9 @@ typedef struct target_sigaltstack {
 #define TARGET_MINSIGSTKSZ    2048
 #define TARGET_SIGSTKSZ       8192
 
+static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state)
+{
+    return state->gregs[15];
+}
+
 #endif /* TARGET_SIGNAL_H */
--- 0001/linux-user/signal.c
+++ work/linux-user/signal.c	2007-11-22 12:52:40.000000000 +0900
@@ -562,6 +562,12 @@ static inline int copy_siginfo_to_user(t
     return 0;
 }
 
+static inline int current_exec_domain_sig(int sig)
+{
+    return /* current->exec_domain && current->exec_domain->signal_invmap
+	      && sig < 32 ? current->exec_domain->signal_invmap[sig] : */ sig;
+}
+
 #if defined(TARGET_I386) && TARGET_ABI_BITS == 32
 
 /* from the Linux kernel */
@@ -745,11 +751,7 @@ static void setup_frame(int sig, struct 
 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
 		goto give_sigsegv;
 
-	err |= __put_user((/*current->exec_domain
-		           && current->exec_domain->signal_invmap
-		           && sig < 32
-		           ? current->exec_domain->signal_invmap[sig]
-		           : */ sig),
+	err |= __put_user(current_exec_domain_sig(sig),
 		          &frame->sig);
 	if (err)
 		goto give_sigsegv;
@@ -819,11 +821,7 @@ static void setup_rt_frame(int sig, stru
 	if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
 		goto give_sigsegv;
 
-	err |= __put_user((/*current->exec_domain
-		    	   && current->exec_domain->signal_invmap
-		    	   && sig < 32
-		    	   ? current->exec_domain->signal_invmap[sig]
-			   : */sig),
+	err |= __put_user(current_exec_domain_sig(sig),
 			  &frame->sig);
         addr = frame_addr + offsetof(struct rt_sigframe, info);
 	err |= __put_user(addr, &frame->pinfo);
@@ -2406,6 +2404,309 @@ long do_rt_sigreturn(CPUState *env)
     return -TARGET_ENOSYS;
 }
 
+#elif defined(TARGET_SH4)
+
+/*
+ * code and data structures from linux kernel:
+ * include/asm-sh/sigcontext.h
+ * arch/sh/kernel/signal.c
+ */
+
+struct target_sigcontext {
+    target_ulong  oldmask;
+
+    /* CPU registers */
+    target_ulong  sc_gregs[16];
+    target_ulong  sc_pc;
+    target_ulong  sc_pr;
+    target_ulong  sc_sr;
+    target_ulong  sc_gbr;
+    target_ulong  sc_mach;
+    target_ulong  sc_macl;
+
+    /* FPU registers */
+    target_ulong  sc_fpregs[16];
+    target_ulong  sc_xfpregs[16];
+    unsigned int sc_fpscr;
+    unsigned int sc_fpul;
+    unsigned int sc_ownedfp;
+};
+
+struct target_sigframe
+{
+    struct target_sigcontext sc;
+    target_ulong extramask[TARGET_NSIG_WORDS-1];
+    uint16_t retcode[3];
+};
+
+
+struct target_ucontext {
+    target_ulong uc_flags;
+    struct target_ucontext *uc_link;
+    target_stack_t uc_stack;
+    struct target_sigcontext uc_mcontext;
+    target_sigset_t uc_sigmask;	/* mask last for extensibility */
+};
+
+struct target_rt_sigframe
+{
+    struct target_siginfo info;
+    struct target_ucontext uc;
+    uint16_t retcode[3];
+};
+
+
+#define MOVW(n)  (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */
+#define TRAP_NOARG 0xc310         /* Syscall w/no args (NR in R3) SH3/4 */
+
+static abi_ulong get_sigframe(struct emulated_sigaction *ka,
+                         unsigned long sp, size_t frame_size)
+{
+    if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+    }
+
+    return (sp - frame_size) & -8ul;
+}
+
+static int setup_sigcontext(struct target_sigcontext *sc,
+			    CPUState *regs, unsigned long mask)
+{
+    int err = 0;
+
+#define COPY(x)         err |= __put_user(regs->x, &sc->sc_##x)
+    COPY(gregs[0]); COPY(gregs[1]);
+    COPY(gregs[2]); COPY(gregs[3]);
+    COPY(gregs[4]); COPY(gregs[5]);
+    COPY(gregs[6]); COPY(gregs[7]);
+    COPY(gregs[8]); COPY(gregs[9]);
+    COPY(gregs[10]); COPY(gregs[11]);
+    COPY(gregs[12]); COPY(gregs[13]);
+    COPY(gregs[14]); COPY(gregs[15]);
+    COPY(gbr); COPY(mach);
+    COPY(macl); COPY(pr);
+    COPY(sr); COPY(pc);
+#undef COPY
+
+    /* todo: save FPU registers here */
+
+    /* non-iBCS2 extensions.. */
+    err |= __put_user(mask, &sc->oldmask);
+
+    return err;
+}
+
+static int restore_sigcontext(struct CPUState *regs,
+			      struct target_sigcontext *sc)
+{
+    unsigned int err = 0;
+
+#define COPY(x)         err |= __get_user(regs->x, &sc->sc_##x)
+    COPY(gregs[1]);
+    COPY(gregs[2]); COPY(gregs[3]);
+    COPY(gregs[4]); COPY(gregs[5]);
+    COPY(gregs[6]); COPY(gregs[7]);
+    COPY(gregs[8]); COPY(gregs[9]);
+    COPY(gregs[10]); COPY(gregs[11]);
+    COPY(gregs[12]); COPY(gregs[13]);
+    COPY(gregs[14]); COPY(gregs[15]);
+    COPY(gbr); COPY(mach);
+    COPY(macl); COPY(pr);
+    COPY(sr); COPY(pc);
+#undef COPY
+
+    /* todo: restore FPU registers here */
+
+    regs->tra = -1;         /* disable syscall checks */
+    return err;
+}
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+			target_sigset_t *set, CPUState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+    int err = 0;
+    int signal;
+
+    frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+    for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
+        err |= __put_user(set->sig[i + 1], &frame->extramask[i]);
+    }
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
+        regs->pr = (unsigned long) ka->sa.sa_restorer;
+    } else {
+        /* Generate return code (system call to sigreturn) */
+        err |= __put_user(MOVW(2), &frame->retcode[0]);
+        err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+        err |= __put_user((TARGET_NR_sigreturn), &frame->retcode[2]);
+        regs->pr = (unsigned long) frame->retcode;
+    }
+
+    if (err)
+        goto give_sigsegv;
+
+    /* Set up registers for signal handler */
+    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[4] = signal; /* Arg for signal handler */
+    regs->gregs[5] = 0;
+    regs->gregs[6] = (unsigned long) &frame->sc;
+    regs->pc = (unsigned long) ka->sa._sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *regs)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    int i;
+    int err = 0;
+    int signal;
+
+    frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+	goto give_sigsegv;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= copy_siginfo_to_user(&frame->info, info);
+
+    /* Create the ucontext.  */
+    err |= __put_user(0, &frame->uc.uc_flags);
+    err |= __put_user(0, (unsigned long *)&frame->uc.uc_link);
+    err |= __put_user((void *)target_sigaltstack_used.ss_sp,
+		      &frame->uc.uc_stack.ss_sp);
+    err |= __put_user(sas_ss_flags(regs->gregs[15]),
+		      &frame->uc.uc_stack.ss_flags);
+    err |= __put_user(target_sigaltstack_used.ss_size,
+		      &frame->uc.uc_stack.ss_size);
+    err |= setup_sigcontext(&frame->uc.uc_mcontext,
+			    regs, set->sig[0]);
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]);
+    }
+
+    /* Set up to return from userspace.  If provided, use a stub
+       already in userspace.  */
+    if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
+        regs->pr = (unsigned long) ka->sa.sa_restorer;
+    } else {
+        /* Generate return code (system call to sigreturn) */
+        err |= __put_user(MOVW(2), &frame->retcode[0]);
+        err |= __put_user(TRAP_NOARG, &frame->retcode[1]);
+        err |= __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]);
+        regs->pr = (unsigned long) frame->retcode;
+    }
+
+    if (err)
+        goto give_sigsegv;
+
+    /* Set up registers for signal handler */
+    regs->gregs[15] = (unsigned long) frame;
+    regs->gregs[4] = signal; /* Arg for signal handler */
+    regs->gregs[5] = (unsigned long) &frame->info;
+    regs->gregs[6] = (unsigned long) &frame->uc;
+    regs->pc = (unsigned long) ka->sa._sa_handler;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+give_sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sig(SIGSEGV);
+}
+
+long do_sigreturn(CPUState *regs)
+{
+    struct target_sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+    target_sigset_t target_set;
+    int i;
+    int err = 0;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_sigreturn\n");
+#endif
+    frame_addr = regs->gregs[15];
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+   	goto badframe;
+
+    err |= __get_user(target_set.sig[0], &frame->sc.oldmask);
+    for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+        err |= (__get_user(target_set.sig[i], &frame->extramask[i - 1]));
+    }
+
+    if (err)
+        goto badframe;
+
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (restore_sigcontext(regs, &frame->sc))
+        goto badframe;
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return regs->gregs[0];
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
+long do_rt_sigreturn(CPUState *regs)
+{
+    struct target_rt_sigframe *frame;
+    abi_ulong frame_addr;
+    sigset_t blocked;
+
+#if defined(DEBUG_SIGNAL)
+    fprintf(stderr, "do_rt_sigreturn\n");
+#endif
+    frame_addr = regs->gregs[15];
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+   	goto badframe;
+
+    target_to_host_sigset(&blocked, &frame->uc.uc_sigmask);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+        goto badframe;
+
+    if (do_sigaltstack(frame_addr +
+		       offsetof(struct target_rt_sigframe, uc.uc_stack),
+		       0, get_sp_from_cpustate(regs)) == -EFAULT)
+        goto badframe;
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return regs->gregs[0];
+
+badframe:
+    unlock_user_struct(frame, frame_addr, 0);
+    force_sig(TARGET_SIGSEGV);
+    return 0;
+}
+
 #else
 
 static void setup_frame(int sig, struct emulated_sigaction *ka,
--- 0001/target-sh4/helper.c
+++ work/target-sh4/helper.c	2007-11-22 12:12:25.000000000 +0900
@@ -39,16 +39,16 @@ int cpu_sh4_handle_mmu_fault(CPUState * 
 			     int mmu_idx, int is_softmmu)
 {
     env->tea = address;
+    env->exception_index = 0;
     switch (rw) {
     case 0:
+	env->tea = address;
         env->exception_index = 0x0a0;
         break;
     case 1:
+	env->tea = address;
         env->exception_index = 0x0c0;
         break;
-    case 2:
-        env->exception_index = 0x0a0;
-        break;
     }
     return 1;
 }
--- 0001/translate-all.c
+++ work/translate-all.c	2007-11-22 12:12:25.000000000 +0900
@@ -298,6 +298,8 @@ int cpu_restore_state(TranslationBlock *
     env->hflags |= gen_opc_hflags[j];
 #elif defined(TARGET_ALPHA)
     env->pc = gen_opc_pc[j];
+#elif defined(TARGET_SH4)
+    env->pc = gen_opc_pc[j];
 #endif
     return 0;
 }

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-11-22  4:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-21  8:16 [Qemu-devel] [PATCH] sh4: add signal handling support for user space emulator Magnus Damm
2007-11-21  8:40 ` Paul Mundt
2007-11-22  4:59   ` Magnus Damm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).