Commit e88d2468 authored by David S. Miller's avatar David S. Miller

sparc: Stash orig_i0 into %g6 instead of %g2

As per the comments added by this commit, %g2 turns out to not be a
usable place to save away orig_i0 for syscall restart handling.

In fact all of %g2, %g3, %g4, and %g5 are assumed to be saved across
a system call by various bits of code in glibc.

%g1 can't be used because that holds the syscall number, which would
need to be saved and restored for syscall restart handling too, and
that would only compound our problems :-)

This leaves us with %g6 and %g7 which are for "system use".  %g7 is
used as the "thread register" by glibc, but %g6 is used as a compiler
and assembler temporary scratch register.  And in no instance is %g6
used to hold a value across a system call.

Therefore %g6 is safe for storing away orig_i0, at least for now.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1d299bc7
...@@ -837,7 +837,7 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs) ...@@ -837,7 +837,7 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs)
if (pt_regs_is_syscall(regs) && if (pt_regs_is_syscall(regs) &&
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
restart_syscall = 1; restart_syscall = 1;
orig_i0 = regs->u_regs[UREG_G2]; orig_i0 = regs->u_regs[UREG_G6];
} }
if (signr > 0) { if (signr > 0) {
......
...@@ -523,12 +523,22 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) ...@@ -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 * register for GDB to save and restore in order to get
* orig_i0 correct for syscall restarts when debugging. * orig_i0 correct for syscall restarts when debugging.
* *
* However, we luckily can use the fact that several registers * Although it should be the case that most of the global
* are volatile across system calls. One such register is * registers are volatile across a system call, glibc already
* %g2, so use that as a place to save away orig_i0. * 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)) 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)) if (test_thread_flag(TIF_RESTORE_SIGMASK))
oldset = &current->saved_sigmask; oldset = &current->saved_sigmask;
...@@ -544,7 +554,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) ...@@ -544,7 +554,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
restart_syscall = 0; restart_syscall = 0;
if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) { if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) {
restart_syscall = 1; restart_syscall = 1;
orig_i0 = regs->u_regs[UREG_G2]; orig_i0 = regs->u_regs[UREG_G6];
} }
......
...@@ -533,13 +533,23 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) ...@@ -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 * register for GDB to save and restore in order to get
* orig_i0 correct for syscall restarts when debugging. * orig_i0 correct for syscall restarts when debugging.
* *
* However, we luckily can use the fact that several registers * Although it should be the case that most of the global
* are volatile across system calls. One such register is * registers are volatile across a system call, glibc already
* %g2, so use that as a place to save away orig_i0. * 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) && if (pt_regs_is_syscall(regs) &&
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) (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) if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask; oldset = &current->saved_sigmask;
...@@ -560,7 +570,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) ...@@ -560,7 +570,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
if (pt_regs_is_syscall(regs) && if (pt_regs_is_syscall(regs) &&
(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
restart_syscall = 1; restart_syscall = 1;
orig_i0 = regs->u_regs[UREG_G2]; orig_i0 = regs->u_regs[UREG_G6];
} }
if (signr > 0) { if (signr > 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment