summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sparc/kernel/signal32.c2
-rw-r--r--arch/sparc/kernel/signal_32.c20
-rw-r--r--arch/sparc/kernel/signal_64.c20
3 files changed, 31 insertions, 11 deletions
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 2e86fd1ddc7b..023b8860dc97 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -837,7 +837,7 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs)
if (pt_regs_is_syscall(regs) &&
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
restart_syscall = 1;
- orig_i0 = regs->u_regs[UREG_G2];
+ orig_i0 = regs->u_regs[UREG_G6];
}
if (signr > 0) {
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 7dfaff64cd6b..d54c6e53aba0 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -523,12 +523,22 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
* register for GDB to save and restore in order to get
* orig_i0 correct for syscall restarts when debugging.
*
- * However, we luckily can use the fact that several registers
- * are volatile across system calls. One such register is
- * %g2, so use that as a place to save away orig_i0.
+ * Although it should be the case that most of the global
+ * registers are volatile across a system call, glibc already
+ * depends upon that fact that we preserve them. So we can't
+ * just use any global register to save away the orig_i0 value.
+ *
+ * In particular %g2, %g3, %g4, and %g5 are all assumed to be
+ * preserved across a system call trap by various pieces of
+ * code in glibc.
+ *
+ * %g7 is used as the "thread register". %g6 is not used in
+ * any fixed manner. %g6 is used as a scratch register and
+ * a compiler temporary, but it's value is never used across
+ * a system call. Therefore %g6 is usable for orig_i0 storage.
*/
if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
- regs->u_regs[UREG_G2] = orig_i0;
+ regs->u_regs[UREG_G6] = orig_i0;
if (test_thread_flag(TIF_RESTORE_SIGMASK))
oldset = &current->saved_sigmask;
@@ -544,7 +554,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
restart_syscall = 0;
if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) {
restart_syscall = 1;
- orig_i0 = regs->u_regs[UREG_G2];
+ orig_i0 = regs->u_regs[UREG_G6];
}
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 1ddf0dedb929..f0836cd0e2f2 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -533,13 +533,23 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
* register for GDB to save and restore in order to get
* orig_i0 correct for syscall restarts when debugging.
*
- * However, we luckily can use the fact that several registers
- * are volatile across system calls. One such register is
- * %g2, so use that as a place to save away orig_i0.
+ * Although it should be the case that most of the global
+ * registers are volatile across a system call, glibc already
+ * depends upon that fact that we preserve them. So we can't
+ * just use any global register to save away the orig_i0 value.
+ *
+ * In particular %g2, %g3, %g4, and %g5 are all assumed to be
+ * preserved across a system call trap by various pieces of
+ * code in glibc.
+ *
+ * %g7 is used as the "thread register". %g6 is not used in
+ * any fixed manner. %g6 is used as a scratch register and
+ * a compiler temporary, but it's value is never used across
+ * a system call. Therefore %g6 is usable for orig_i0 storage.
*/
if (pt_regs_is_syscall(regs) &&
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
- regs->u_regs[UREG_G2] = orig_i0;
+ regs->u_regs[UREG_G6] = orig_i0;
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
@@ -560,7 +570,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
if (pt_regs_is_syscall(regs) &&
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
restart_syscall = 1;
- orig_i0 = regs->u_regs[UREG_G2];
+ orig_i0 = regs->u_regs[UREG_G6];
}
if (signr > 0) {