mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 09:59:32 +00:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1d299bc773
commit
e88d246871
3 changed files with 31 additions and 11 deletions
|
@ -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) {
|
||||
|
|
|
@ -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 = ¤t->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];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 = ¤t->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) {
|
||||
|
|
Loading…
Reference in a new issue