From patchwork Tue Nov 15 21:07:29 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Miller X-Patchwork-Id: 125871 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id D17F4B6F8A for ; Wed, 16 Nov 2011 08:07:34 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932318Ab1KOVHd (ORCPT ); Tue, 15 Nov 2011 16:07:33 -0500 Received: from shards.monkeyblade.net ([198.137.202.13]:38408 "EHLO shards.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932298Ab1KOVHd (ORCPT ); Tue, 15 Nov 2011 16:07:33 -0500 Received: from localhost (cpe-66-65-61-233.nyc.res.rr.com [66.65.61.233]) (authenticated bits=0) by shards.monkeyblade.net (8.14.4/8.14.4) with ESMTP id pAFL7TEo026567 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 15 Nov 2011 13:07:32 -0800 Date: Tue, 15 Nov 2011 16:07:29 -0500 (EST) Message-Id: <20111115.160729.517452082832358119.davem@davemloft.net> To: sparclinux@vger.kernel.org Subject: Re: [PATCH] sparc: Fix handling of orig_i0 wrt. debugging when restarting syscalls. From: David Miller In-Reply-To: <20111115.124032.1821407186517169645.davem@davemloft.net> References: <20111114.235351.467624122814997359.davem@davemloft.net> <20111115.124032.1821407186517169645.davem@davemloft.net> X-Mailer: Mew version 6.3 on Emacs 23.2 / Mule 6.0 (HANACHIRUSATO) Mime-Version: 1.0 X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.2.6 (shards.monkeyblade.net [198.137.202.13]); Tue, 15 Nov 2011 13:07:33 -0800 (PST) Sender: sparclinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: sparclinux@vger.kernel.org From: David Miller Date: Tue, 15 Nov 2011 12:40:32 -0500 (EST) > From: David Miller > Date: Mon, 14 Nov 2011 23:53:51 -0500 (EST) > >> Luckily we can solve this problem without having to make debuggers >> aware of the issue. Across system calls, several registers are >> considered volatile and can be safely clobbered. >> >> Therefore we use the pt_regs save area of one of those registers, %g2, >> as a place to save and restore orig_i0. > > Unfortunately this doesn't work, for example the clone implementation > in glibc expects %g2 and several other global registers to be preserved > across a system call. > > I'll need to find another place to stash this value away. Ok, here is how I've decided to handle this: -------------------- [PATCH] 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 --- arch/sparc/kernel/signal32.c | 2 +- arch/sparc/kernel/signal_32.c | 20 +++++++++++++++----- 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 2e86fd1..023b886 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 7dfaff6..d54c6e5 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 = ¤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]; } diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 1ddf0de..f0836cd 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 = ¤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) {