diff options
author | David S. Miller <davem@davemloft.net> | 2011-11-15 15:57:00 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-15 15:57:00 -0500 |
commit | e88d2468718b0789b4c33da2f7e1cef2a1eee279 (patch) | |
tree | beb5a9eff292f1faa05eb9b96b7f1bd7815da131 /arch/sparc/kernel | |
parent | 1d299bc7732c34d85bd43ac1a8745f5a2fed2078 (diff) |
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>
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/signal32.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/signal_32.c | 20 | ||||
-rw-r--r-- | arch/sparc/kernel/signal_64.c | 20 |
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) | |||
837 | if (pt_regs_is_syscall(regs) && | 837 | if (pt_regs_is_syscall(regs) && |
838 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { | 838 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { |
839 | restart_syscall = 1; | 839 | restart_syscall = 1; |
840 | orig_i0 = regs->u_regs[UREG_G2]; | 840 | orig_i0 = regs->u_regs[UREG_G6]; |
841 | } | 841 | } |
842 | 842 | ||
843 | if (signr > 0) { | 843 | 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) | |||
523 | * register for GDB to save and restore in order to get | 523 | * register for GDB to save and restore in order to get |
524 | * orig_i0 correct for syscall restarts when debugging. | 524 | * orig_i0 correct for syscall restarts when debugging. |
525 | * | 525 | * |
526 | * However, we luckily can use the fact that several registers | 526 | * Although it should be the case that most of the global |
527 | * are volatile across system calls. One such register is | 527 | * registers are volatile across a system call, glibc already |
528 | * %g2, so use that as a place to save away orig_i0. | 528 | * depends upon that fact that we preserve them. So we can't |
529 | * just use any global register to save away the orig_i0 value. | ||
530 | * | ||
531 | * In particular %g2, %g3, %g4, and %g5 are all assumed to be | ||
532 | * preserved across a system call trap by various pieces of | ||
533 | * code in glibc. | ||
534 | * | ||
535 | * %g7 is used as the "thread register". %g6 is not used in | ||
536 | * any fixed manner. %g6 is used as a scratch register and | ||
537 | * a compiler temporary, but it's value is never used across | ||
538 | * a system call. Therefore %g6 is usable for orig_i0 storage. | ||
529 | */ | 539 | */ |
530 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) | 540 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) |
531 | regs->u_regs[UREG_G2] = orig_i0; | 541 | regs->u_regs[UREG_G6] = orig_i0; |
532 | 542 | ||
533 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 543 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
534 | oldset = ¤t->saved_sigmask; | 544 | oldset = ¤t->saved_sigmask; |
@@ -544,7 +554,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
544 | restart_syscall = 0; | 554 | restart_syscall = 0; |
545 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) { | 555 | if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) { |
546 | restart_syscall = 1; | 556 | restart_syscall = 1; |
547 | orig_i0 = regs->u_regs[UREG_G2]; | 557 | orig_i0 = regs->u_regs[UREG_G6]; |
548 | } | 558 | } |
549 | 559 | ||
550 | 560 | ||
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) | |||
533 | * register for GDB to save and restore in order to get | 533 | * register for GDB to save and restore in order to get |
534 | * orig_i0 correct for syscall restarts when debugging. | 534 | * orig_i0 correct for syscall restarts when debugging. |
535 | * | 535 | * |
536 | * However, we luckily can use the fact that several registers | 536 | * Although it should be the case that most of the global |
537 | * are volatile across system calls. One such register is | 537 | * registers are volatile across a system call, glibc already |
538 | * %g2, so use that as a place to save away orig_i0. | 538 | * depends upon that fact that we preserve them. So we can't |
539 | * just use any global register to save away the orig_i0 value. | ||
540 | * | ||
541 | * In particular %g2, %g3, %g4, and %g5 are all assumed to be | ||
542 | * preserved across a system call trap by various pieces of | ||
543 | * code in glibc. | ||
544 | * | ||
545 | * %g7 is used as the "thread register". %g6 is not used in | ||
546 | * any fixed manner. %g6 is used as a scratch register and | ||
547 | * a compiler temporary, but it's value is never used across | ||
548 | * a system call. Therefore %g6 is usable for orig_i0 storage. | ||
539 | */ | 549 | */ |
540 | if (pt_regs_is_syscall(regs) && | 550 | if (pt_regs_is_syscall(regs) && |
541 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) | 551 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) |
542 | regs->u_regs[UREG_G2] = orig_i0; | 552 | regs->u_regs[UREG_G6] = orig_i0; |
543 | 553 | ||
544 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) | 554 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) |
545 | oldset = ¤t->saved_sigmask; | 555 | oldset = ¤t->saved_sigmask; |
@@ -560,7 +570,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
560 | if (pt_regs_is_syscall(regs) && | 570 | if (pt_regs_is_syscall(regs) && |
561 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { | 571 | (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { |
562 | restart_syscall = 1; | 572 | restart_syscall = 1; |
563 | orig_i0 = regs->u_regs[UREG_G2]; | 573 | orig_i0 = regs->u_regs[UREG_G6]; |
564 | } | 574 | } |
565 | 575 | ||
566 | if (signr > 0) { | 576 | if (signr > 0) { |