patch-2.3.7 linux/arch/arm/kernel/signal.c
Next file: linux/arch/arm/kernel/sys_arm.c
Previous file: linux/arch/arm/kernel/setup.c
Back to the patch index
Back to the overall index
- Lines: 232
- Date:
Thu Jun 17 01:11:35 1999
- Orig file:
v2.3.6/linux/arch/arm/kernel/signal.c
- Orig date:
Thu Oct 8 09:32:22 1998
diff -u --recursive --new-file v2.3.6/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c
@@ -28,7 +28,7 @@
asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr,
int options, unsigned long *ru);
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs);
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
extern int ptrace_cancel_bpt (struct task_struct *);
extern int ptrace_set_bpt (struct task_struct *);
@@ -50,7 +50,7 @@
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&saveset, regs))
+ if (do_signal(&saveset, regs, 0))
return regs->ARM_r0;
}
}
@@ -78,7 +78,7 @@
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(&saveset, regs))
+ if (do_signal(&saveset, regs, 0))
return regs->ARM_r0;
}
}
@@ -158,12 +158,8 @@
#ifdef CONFIG_CPU_32
err |= __get_user(regs->ARM_cpsr, &sc->arm_cpsr);
#endif
- if (!valid_user_regs(regs))
- return 1;
- /* send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt (current))
- send_sig (SIGTRAP, current, 1);
+ err |= !valid_user_regs(regs);
return err;
}
@@ -173,6 +169,14 @@
struct sigframe *frame;
sigset_t set;
+ /*
+ * Since we stacked the signal on a word boundary,
+ * then 'sp' should be word aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ if (regs->ARM_sp & 3)
+ goto badframe;
+
frame = (struct sigframe *)regs->ARM_sp;
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
@@ -192,6 +196,10 @@
if (restore_sigcontext(regs, &frame->sc))
goto badframe;
+ /* Send SIGTRAP if we're single-stepping */
+ if (ptrace_cancel_bpt (current))
+ send_sig(SIGTRAP, current, 1);
+
return regs->ARM_r0;
badframe:
@@ -204,6 +212,14 @@
struct rt_sigframe *frame;
sigset_t set;
+ /*
+ * Since we stacked the signal on a word boundary,
+ * then 'sp' should be word aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ if (regs->ARM_sp & 3)
+ goto badframe;
+
frame = (struct rt_sigframe *)regs->ARM_sp;
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
@@ -220,6 +236,10 @@
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
+ /* Send SIGTRAP if we're single-stepping */
+ if (ptrace_cancel_bpt (current))
+ send_sig(SIGTRAP, current, 1);
+
return regs->ARM_r0;
badframe:
@@ -260,6 +280,26 @@
return err;
}
+static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ unsigned long framesize)
+{
+ unsigned long sp = regs->ARM_sp;
+
+ /*
+ * This is the X/Open sanctioned signal stack switching.
+ */
+ if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+
+ /*
+ * No matter what happens, 'sp' must be word
+ * aligned otherwise nasty things could happen
+ */
+ sp &= ~3;
+
+ return (void *)(sp - framesize);
+}
+
static void setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs)
{
@@ -267,9 +307,9 @@
unsigned long retcode;
int err = 0;
- frame = (struct sigframe *)regs->ARM_sp - 1;
+ frame = get_sigframe(ka, regs, sizeof(*frame));
- if (!access_ok(VERIFT_WRITE, frame, sizeof (*frame)))
+ if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto segv_and_exit;
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
@@ -286,7 +326,7 @@
} else {
retcode = (unsigned long)&frame->retcode;
err |= __put_user(SWI_SYS_SIGRETURN, &frame->retcode);
- __flush_entry_to_ram (&frame->retcode);
+ flush_icache_range(retcode, retcode + 4);
}
if (err)
@@ -299,6 +339,11 @@
regs->ARM_sp = (unsigned long)frame;
regs->ARM_lr = retcode;
regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
+#if defined(CONFIG_CPU_32)
+ /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */
+ if (ka->sa.sa_flags & SA_THIRTYTWO)
+ regs->ARM_cpsr = USR_MODE;
+#endif
if (valid_user_regs(regs))
return;
@@ -315,7 +360,8 @@
unsigned long retcode;
int err = 0;
- frame = (struct rt_sigframe *)regs->ARM_sp - 1;
+ frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe));
+
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto segv_and_exit;
@@ -337,7 +383,7 @@
} else {
retcode = (unsigned long)&frame->retcode;
err |= __put_user(SWI_SYS_RT_SIGRETURN, &frame->retcode);
- __flush_entry_to_ram (&frame->retcode);
+ flush_icache_range(retcode, retcode + 4);
}
if (err)
@@ -350,6 +396,11 @@
regs->ARM_sp = (unsigned long)frame;
regs->ARM_lr = retcode;
regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
+#if defined(CONFIG_CPU_32)
+ /* Maybe we need to deliver a 32-bit signal to a 26-bit task. */
+ if (ka->sa.sa_flags & SA_THIRTYTWO)
+ regs->ARM_cpsr = USR_MODE;
+#endif
if (valid_user_regs(regs))
return;
@@ -393,18 +444,25 @@
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{
- unsigned long instr, *pc = (unsigned long *)(instruction_pointer(regs)-4);
struct k_sigaction *ka;
siginfo_t info;
- int single_stepping, swi_instr;
+ int single_stepping;
+
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (!user_mode(regs))
+ return 0;
if (!oldset)
oldset = ¤t->blocked;
single_stepping = ptrace_cancel_bpt (current);
- swi_instr = (!get_user (instr, pc) && (instr & 0x0f000000) == 0x0f000000);
for (;;) {
unsigned long signr;
@@ -503,7 +561,7 @@
}
/* Are we from a system call? */
- if (swi_instr) {
+ if (syscall) {
switch (regs->ARM_r0) {
case -ERESTARTNOHAND:
regs->ARM_r0 = -EINTR;
@@ -527,7 +585,7 @@
return 1;
}
- if (swi_instr &&
+ if (syscall &&
(regs->ARM_r0 == -ERESTARTNOHAND ||
regs->ARM_r0 == -ERESTARTSYS ||
regs->ARM_r0 == -ERESTARTNOINTR)) {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)