VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / s390 / kernel / compat_signal.c
index 67134ee..e8c8b2f 100644 (file)
@@ -40,6 +40,7 @@ typedef struct
        __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
        struct sigcontext32 sc;
        _sigregs32 sregs;
+       int signo;
        __u8 retcode[S390_SYSCALL_SIZE];
 } sigframe32;
 
@@ -105,6 +106,53 @@ int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from)
        return err;
 }
 
+int copy_siginfo_from_user32(siginfo_t *to, siginfo_t32 __user *from)
+{
+       int err;
+       u32 tmp;
+
+       if (!access_ok (VERIFY_READ, from, sizeof(siginfo_t32)))
+               return -EFAULT;
+
+       err = __get_user(to->si_signo, &from->si_signo);
+       err |= __get_user(to->si_errno, &from->si_errno);
+       err |= __get_user(to->si_code, &from->si_code);
+
+       if (from->si_code < 0)
+               err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+       else {
+               switch (from->si_code >> 16) {
+               case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
+               case __SI_MESGQ >> 16:
+                       err |= __get_user(to->si_int, &from->si_int);
+                       /* fallthrough */
+               case __SI_KILL >> 16:
+                       err |= __get_user(to->si_pid, &from->si_pid);
+                       err |= __get_user(to->si_uid, &from->si_uid);
+                       break;
+               case __SI_CHLD >> 16:
+                       err |= __get_user(to->si_pid, &from->si_pid);
+                       err |= __get_user(to->si_uid, &from->si_uid);
+                       err |= __get_user(to->si_utime, &from->si_utime);
+                       err |= __get_user(to->si_stime, &from->si_stime);
+                       err |= __get_user(to->si_status, &from->si_status);
+                       break;
+               case __SI_FAULT >> 16:
+                       err |= __get_user(tmp, &from->si_addr);
+                       to->si_addr = (void *)(u64) (tmp & PSW32_ADDR_INSN);
+                       break;
+               case __SI_POLL >> 16:
+               case __SI_TIMER >> 16:
+                       err |= __get_user(to->si_band, &from->si_band);
+                       err |= __get_user(to->si_fd, &from->si_fd);
+                       break;
+               default:
+                       break;
+               }
+       }
+       return err;
+}
+
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -497,6 +545,10 @@ static void setup_frame32(int sig, struct k_sigaction *ka,
           To avoid breaking binary compatibility, they are passed as args. */
        regs->gprs[4] = current->thread.trap_no;
        regs->gprs[5] = current->thread.prot_addr;
+
+       /* Place signal number on stack to allow backtrace from handler.  */
+       if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
+               goto give_sigsegv;
        return;
 
 give_sigsegv: