patch: POSIX.1b signals for ppc
Giovanna Ambrosini
ambrosini at lightning.ch
Sat May 20 01:06:10 EST 2000
Hello Cort,
I prepared a new patch against the latest official kernel, as you asked me.
I tested it and worked fine.
Cort Dougan wrote:
>
> If you could send me the a patch against a more recent kernel in a few days
> I can merge it in. I'll be gone until the 22nd, though.
diff -urN linux-2.3.99-pre8/arch/ppc/kernel/entry.S linux-2.3.99-pre8-ga/arch/ppc/kernel/entry.S
--- linux-2.3.99-pre8/arch/ppc/kernel/entry.S Wed Feb 23 07:27:42 2000
+++ linux-2.3.99-pre8-ga/arch/ppc/kernel/entry.S Thu May 18 10:12:30 2000
@@ -20,6 +20,10 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
+ *
+ * 2000-04-10.
+ * Add sys_rt_sigreturn in DoSyscall Handler.
+ * Giovanna Ambrosini (ambrosini at lightning.ch).
*
*/
@@ -83,6 +87,8 @@
#endif /* SHOW_SYSCALLS */
cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
beq- 10f
+ cmpi 0,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */
+ beq- 16f
lwz r10,TASK_FLAGS(r2)
andi. r10,r10,PF_TRACESYS
bne- 50f
@@ -129,6 +135,12 @@
/* sys_sigreturn */
10: addi r3,r1,STACK_FRAME_OVERHEAD
bl sys_sigreturn
+ cmpi 0,r3,0 /* Check for restarted system call */
+ bge ret_from_except
+ b 20b
+/* sys_rt_sigreturn */
+16: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl sys_rt_sigreturn
cmpi 0,r3,0 /* Check for restarted system call */
bge ret_from_except
b 20b
diff -urN linux-2.3.99-pre8/arch/ppc/kernel/signal.c linux-2.3.99-pre8-ga/arch/ppc/kernel/signal.c
--- linux-2.3.99-pre8/arch/ppc/kernel/signal.c Fri Nov 19 04:37:03 1999
+++ linux-2.3.99-pre8-ga/arch/ppc/kernel/signal.c Thu May 18 10:12:30 2000
@@ -14,6 +14,16 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
+ *
+ *
+ * 2000-04-7.
+ * Define a real-time signal frame with siginfo and ucontext
+ * structures (setup_rt_frame()).
+ * Stuck up a real-time signal frame when setting the signal
+ * frame with SA_SIGINFO flags.
+ * Add sys_rt_sigreturn() to undo the signal stack.
+ *
+ * Giovanna Ambrosini (ambrosini at lightning.ch)
*/
#include <linux/sched.h>
@@ -121,13 +131,6 @@
}
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
-{
- printk("sys_rt_sigreturn(): %s/%d not yet implemented.\n",
- current->comm,current->pid);
- do_exit(SIGSEGV);
-}
-
asmlinkage int
sys_sigaltstack(const stack_t *uss, stack_t *uoss)
{
@@ -171,13 +174,11 @@
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* a sigregs struct
- * one or more sigcontext structs
+ * one or more sigcontext structs with
* a gap of __SIGNAL_FRAMESIZE bytes
*
* Each of these things must be a multiple of 16 bytes in size.
*
- * XXX ultimately we will have to stack up a siginfo and ucontext
- * for each rt signal.
*/
struct sigregs {
elf_gregset_t gp_regs;
@@ -188,6 +189,15 @@
int abigap[56];
};
+struct rt_sigframe
+{
+ unsigned long _unused[2];
+ struct siginfo *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+};
+
/*
* Do a signal return; undo the signal stack.
*/
@@ -255,6 +265,91 @@
do_exit(SIGSEGV);
}
+
+/*
+ * When we have rt signals to deliver, we set up on the
+ * user stack, going down from the original stack pointer:
+ * a sigregs struct
+ * one rt_sigframe struct (siginfo + ucontext)
+ * a gap of __SIGNAL_FRAMESIZE bytes
+ *
+ * Each of these things must be a multiple of 16 bytes in size.
+ *
+ */
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_sigframe *rt_sf;
+ struct sigcontext_struct sigctx;
+ struct sigregs *sr;
+ int ret;
+ elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
+ sigset_t set;
+ stack_t st;
+ unsigned long prevsp;
+
+ rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
+ || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
+ || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+ goto badframe;
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(¤t->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ rt_sf++; /* Look at next rt_sigframe */
+ if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
+ /* Last stacked signal - restore registers -
+ * sigctx is initialized to point to the
+ * preamble frame (where registers are stored)
+ * see handle_signal()
+ */
+ sr = (struct sigregs *) sigctx.regs;
+ if (regs->msr & MSR_FP )
+ giveup_fpu(current);
+ if (copy_from_user(saved_regs, &sr->gp_regs,
+ sizeof(sr->gp_regs)))
+ goto badframe;
+ saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+ | (saved_regs[PT_MSR] & MSR_USERCHANGE);
+ memcpy(regs, saved_regs, GP_REGS_SIZE);
+ if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+ sizeof(sr->fp_regs)))
+ goto badframe;
+ /* This function sets back the stack flags into
+ the current task structure. */
+ sys_sigaltstack(&st, NULL);
+
+ ret = regs->result;
+ } else {
+ /* More signals to go */
+ /* Set up registers for next signal handler */
+ regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
+ if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
+ goto badframe;
+ sr = (struct sigregs *) sigctx.regs;
+ regs->gpr[3] = ret = sigctx.signal;
+ /* Get the siginfo */
+ get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
+ /* Get the ucontext */
+ get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
+ regs->gpr[6] = (unsigned long) rt_sf;
+
+ regs->link = (unsigned long) &sr->tramp;
+ regs->nip = sigctx.handler;
+ if (get_user(prevsp, &sr->gp_regs[PT_R1])
+ || put_user(prevsp, (unsigned long *) regs->gpr[1]))
+ goto badframe;
+ }
+ return ret;
+
+badframe:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+
/*
* Set up a signal frame.
*/
@@ -297,6 +392,57 @@
do_exit(SIGSEGV);
}
+
+static void
+setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
+ signed long newsp)
+{
+ struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
+
+ /* Set up preamble frame */
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto badframe;
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
+ if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
+ || __copy_to_user(&frame->fp_regs, current->thread.fpr,
+ ELF_NFPREG * sizeof(double))
+ /* Set up to return from user space.
+ It calls the sc exception at offset 0x9999
+ for sys_rt_sigreturn().
+ */
+ || __put_user(0x38006666UL, &frame->tramp[0]) /* li r0,0x6666 */
+ || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */
+ goto badframe;
+ flush_icache_range((unsigned long) &frame->tramp[0],
+ (unsigned long) &frame->tramp[2]);
+
+ /* Retrieve rt_sigframe from stack and
+ set up registers for signal handler
+ */
+ newsp -= __SIGNAL_FRAMESIZE;
+ if (put_user(regs->gpr[1], (unsigned long *)newsp)
+ || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler)
+ || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
+ || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
+ || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
+ goto badframe;
+
+ regs->gpr[1] = newsp;
+ regs->gpr[6] = (unsigned long) rt_sf;
+ regs->link = (unsigned long) frame->tramp;
+
+ return;
+
+badframe:
+#if DEBUG_SIG
+ printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
+ regs, frame, newsp);
+#endif
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
/*
* OK, we're invoking a handler
*/
@@ -306,6 +452,7 @@
unsigned long *newspp, unsigned long frame)
{
struct sigcontext_struct *sc;
+ struct rt_sigframe *rt_sf;
if (regs->trap == 0x0C00 /* System Call! */
&& ((int)regs->result == -ERESTARTNOHAND ||
@@ -313,20 +460,47 @@
!(ka->sa.sa_flags & SA_RESTART))))
regs->result = -EINTR;
- /* Put another sigcontext on the stack */
- *newspp -= sizeof(*sc);
- sc = (struct sigcontext_struct *) *newspp;
- if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
- goto badframe;
+ /* Set up Signal Frame */
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+ /* Put a Real Time Context onto stack */
+ *newspp -= sizeof(*rt_sf);
+ rt_sf = (struct rt_sigframe *) *newspp;
+ if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
+ goto badframe;
- if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
- || __put_user(oldset->sig[0], &sc->oldmask)
+ if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
+ || __put_user(&rt_sf->info, &rt_sf->pinfo)
+ || __put_user(&rt_sf->uc, &rt_sf->puc)
+ /* Put the siginfo */
+ || __copy_to_user(&rt_sf->info, info, sizeof(*info))
+ /* Create the ucontext */
+ || __put_user(0, &rt_sf->uc.uc_flags)
+ || __put_user(0, &rt_sf->uc.uc_link)
+ || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
+ || __put_user(sas_ss_flags(regs->gpr[1]),
+ &rt_sf->uc.uc_stack.ss_flags)
+ || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
+ || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
+ /* mcontext.regs points to preamble register frame */
+ || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
+ || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
+ goto badframe;
+ } else {
+ /* Put another sigcontext on the stack */
+ *newspp -= sizeof(*sc);
+ sc = (struct sigcontext_struct *) *newspp;
+ if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+ goto badframe;
+
+ if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+ || __put_user(oldset->sig[0], &sc->oldmask)
#if _NSIG_WORDS > 1
- || __put_user(oldset->sig[1], &sc->_unused[3])
+ || __put_user(oldset->sig[1], &sc->_unused[3])
#endif
- || __put_user((struct pt_regs *)frame, &sc->regs)
- || __put_user(sig, &sc->signal))
- goto badframe;
+ || __put_user((struct pt_regs *)frame, &sc->regs)
+ || __put_user(sig, &sc->signal))
+ goto badframe;
+ }
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
@@ -482,7 +656,10 @@
if (newsp == frame)
return 0; /* no signals delivered */
- setup_frame(regs, (struct sigregs *) frame, newsp);
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(regs, (struct sigregs *) frame, newsp);
+ else
+ setup_frame(regs, (struct sigregs *) frame, newsp);
return 1;
}
diff -urN linux-2.3.99-pre8/include/asm-ppc/ucontext.h linux-2.3.99-pre8-ga/include/asm-ppc/ucontext.h
--- linux-2.3.99-pre8/include/asm-ppc/ucontext.h Sun Nov 28 00:42:33 1999
+++ linux-2.3.99-pre8-ga/include/asm-ppc/ucontext.h Thu May 18 10:12:30 2000
@@ -7,6 +7,7 @@
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
+ struct sigcontext_struct uc_mcontext;
sigset_t uc_sigmask; /* mask last for extensibility */
};
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
More information about the Linuxppc-dev
mailing list