This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] PowerPC: Add Program Priority Register support


On 08/15/2012 12:06 PM, Adhemerval Zanella wrote:
> Thanks again, Ryan.
>
> On 08/14/2012 03:03 PM, Ryan S. Arnold wrote:
>
>> With my explanation in mind, I think this comment isn't quite correct.
>>  It should read as something like the following:
>>
>> /* The value in the Priority Program Register (PPR) is saved and restored
>>    by moving its value to, and fetching its value from, a field preceding the
>>    TCB that is reserved by the TLS ABI for "other thread library information".
>>    Since it is the loader's responsibility to setup the TCB (and the fields in
>>    the reserved space), the PPR save/restore facility is only available outside
>>    of the loader.  */
>>
>> You could add a comment that the loader always, therefore, runs in the
>> default thread priority.
>> ...
>>
>>> diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h
>>> index ed96478..79566be 100644
>>> --- a/sysdeps/powerpc/powerpc64/sysdep.h
>>> +++ b/sysdeps/powerpc/powerpc64/sysdep.h
>>> @@ -205,9 +205,26 @@ LT_LABELSUFFIX(name,_name_end): ; \
>>>    TRACEBACK_MASK(name,mask)    \
>>>    END_2(name)
>>>
>>> +/* The Priority Program Register (PPR) is saved and restored by moving its
>>> +   value to ppr field in TBC. Since it is the loader responsible to setup the
>>> +   TBC, the code is only built if not within the loader.  */
>> Same comment applies as for ppc32.
>>
>> Ryan S. Arnold
>>
> Fair enough, comments changed to your suggestion.
>
>
Resulting patch after your two reviews below:

---

2012-08-15 Adhemerval Zanella  <azanella@linux.vnet.ibm.com>

	* sysdeps/powerpc/powerpc32/sysdep.h: Added Program Priority Register
	(PPR) set/restore support for ISA 2.03+.
	* sysdeps/powerpc/powerpc64/sysdep.h: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/syscall.S: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/____longjmp_chk.S:
	Likewise.
 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext-common.S:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext-common.S:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/____longjmp_chk.S:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/setcontext.S:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/swapcontext.S:
	Likewise.
	* sysdeps/powerpc/sys/platform/ppc.h: Add PPR set functions.
	* manual/platform.texi: Document PPR set functions.
	* nptl/sysdeps/powerpc/tls.h: Add PPR field to TCB.
	* sysdeps/powerpc/test-saveppr.c: New file: test PPR set/restore in
	syscalls.
	* sysdeps/powerpc/Makefile: Add test-saveppr test.
	* nptl/sysdeps/powerpc/tcb-offsets.sym: Add PPR field offset value
	in TCB.
	* sysdeps/powerpc/powerpc32/stackguard-macros.h: Updated stack_guard
	offset value.
	* sysdeps/powerpc/powerpc64/stackguard-macros.h: Likewise.

diff --git a/manual/platform.texi b/manual/platform.texi
index 02b5c55..834b091 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -26,3 +26,24 @@ different from the processor frequency.  More information is available in
 without requiring assistance from the operating system, so it is very
 efficient.
 @end deftypefun
+
+@deftypefun {void} __ppc_set_ppr_med (void)
+Set the Program Priority Register to medium value (default).
+
+The @dfn{Program Priority Register} (PPR) is a 64-bit register that controls
+the program's priority. By adjusting the PPR value the programmer may
+improve system throughput by causing the system resources to be used
+more efficiently, especially in contention situations.
+The three unprivileged states available are covered by the functions
+__ppc_set_ppr_med (medium - default), __ppc_set_ppc_low (low) and
+__ppc_set_ppc_med_low (medium low).  More information
+available in @cite{Power ISA 2.06b - Book II - Section 3.1}.
+@end deftypefun
+
+@deftypefun {void} __ppc_set_ppr_low (void)
+Set the Program Priority Register to low value.
+@end deftypefun
+
+@deftypefun {void} __ppc_set_ppr_med_low (void)
+Set the Program Priority Register to medium low value.
+@end deftypefun
diff --git a/nptl/sysdeps/powerpc/tcb-offsets.sym b/nptl/sysdeps/powerpc/tcb-offsets.sym
index 8ac133d..7f65b9f 100644
--- a/nptl/sysdeps/powerpc/tcb-offsets.sym
+++ b/nptl/sysdeps/powerpc/tcb-offsets.sym
@@ -14,6 +14,7 @@ MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads)
 #endif
 PID				thread_offsetof (pid)
 TID				thread_offsetof (tid)
+PPR_OFFSET			(offsetof (tcbhead_t, ppr) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
 POINTER_GUARD			(offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
 #ifndef __ASSUME_PRIVATE_FUTEX
 PRIVATE_FUTEX_OFFSET		thread_offsetof (header.private_futex)
diff --git a/nptl/sysdeps/powerpc/tls.h b/nptl/sysdeps/powerpc/tls.h
index 4c09eec..6ed6e65 100644
--- a/nptl/sysdeps/powerpc/tls.h
+++ b/nptl/sysdeps/powerpc/tls.h
@@ -1,5 +1,5 @@
 /* Definition for thread-local data handling.  NPTL/PowerPC version.
-   Copyright (C) 2003, 2005, 2006, 2007, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2003-2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -61,6 +61,8 @@ typedef union dtv
    are private.  */
 typedef struct
 {
+  /* Program Priority Register saved value.  */
+  uint64_t  ppr;
   uintptr_t pointer_guard;
   uintptr_t stack_guard;
   dtv_t *dtv;
diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
index 79dd6fa..371e845 100644
--- a/sysdeps/powerpc/Makefile
+++ b/sysdeps/powerpc/Makefile
@@ -29,5 +29,5 @@ endif
 
 ifeq ($(subdir),misc)
 sysdep_headers += sys/platform/ppc.h
-tests += test-gettimebase
+tests += test-gettimebase test-saveppr
 endif
diff --git a/sysdeps/powerpc/powerpc32/stackguard-macros.h b/sysdeps/powerpc/powerpc32/stackguard-macros.h
index 839f6a4..65171bc 100644
--- a/sysdeps/powerpc/powerpc32/stackguard-macros.h
+++ b/sysdeps/powerpc/powerpc32/stackguard-macros.h
@@ -1,4 +1,8 @@
 #include <stdint.h>
 
 #define STACK_CHK_GUARD \
-  ({ uintptr_t x; asm ("lwz %0,-28680(2)" : "=r" (x)); x; })
+  ({ uintptr_t x; \
+     asm ("lwz %0,%1(2)" : "=r" (x) \
+	  : "i" (offsetof (tcbhead_t, stack_guard) \
+	         - TLS_TCB_OFFSET - sizeof (tcbhead_t))); \
+     x; })
diff --git a/sysdeps/powerpc/powerpc32/sysdep.h b/sysdeps/powerpc/powerpc32/sysdep.h
index 02917a8..5756489 100644
--- a/sysdeps/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/powerpc/powerpc32/sysdep.h
@@ -89,9 +89,29 @@ GOT_LABEL:			;					      \
   cfi_endproc;								      \
   ASM_SIZE_DIRECTIVE(name)
 
+/* The value in the Priority Program Register (PPR) is saved and restored
+   by moving its value to, and fetching its value from, a field preceding the
+   TCB that is reserved by the TLS ABI for "other thread library information".
+   Since it is the loader's responsibility to setup the TCB (and the fields in
+   the reserved space), the PPR save/restore facility is only available outside
+   of the loader.  */
+#if defined(_ARCH_PWR5X) && !defined(IS_IN_rtld) && defined(IN_LIB)
+#define SAVE_PPR \
+  mfspr r0,896;								      \
+  std   r0,PPR_OFFSET(r2);
+#define RESTORE_PPR \
+  ld    r0,PPR_OFFSET(r2);						      \
+  mtspr 896,r0;
+#else
+#define SAVE_PPR
+#define RESTORE_PPR
+#endif
+
 #define DO_CALL(syscall)						      \
+    SAVE_PPR								      \
     li 0,syscall;							      \
-    sc
+    sc;									      \
+    RESTORE_PPR
 
 #undef JUMPTARGET
 #ifdef PIC
diff --git a/sysdeps/powerpc/powerpc64/stackguard-macros.h b/sysdeps/powerpc/powerpc64/stackguard-macros.h
index 9da879c..667ba2d 100644
--- a/sysdeps/powerpc/powerpc64/stackguard-macros.h
+++ b/sysdeps/powerpc/powerpc64/stackguard-macros.h
@@ -1,4 +1,8 @@
 #include <stdint.h>
 
 #define STACK_CHK_GUARD \
-  ({ uintptr_t x; asm ("ld %0,-28688(13)" : "=r" (x)); x; })
+  ({ uintptr_t x; \
+     asm ("ld %0,%1(13)" : "=r" (x) \
+          : "i" (offsetof (tcbhead_t, stack_guard) \
+	         - TLS_TCB_OFFSET - sizeof (tcbhead_t))); \
+     x; })
diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h
index ed96478..d7cac63 100644
--- a/sysdeps/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/powerpc/powerpc64/sysdep.h
@@ -205,9 +205,29 @@ LT_LABELSUFFIX(name,_name_end): ; \
   TRACEBACK_MASK(name,mask)	\
   END_2(name)
 
+/* The value in the Priority Program Register (PPR) is saved and restored
+   by moving its value to, and fetching its value from, a field preceding the
+   TCB that is reserved by the TLS ABI for "other thread library information".
+   Since it is the loader's responsibility to setup the TCB (and the fields in
+   the reserved space), the PPR save/restore facility is only available outside
+   of the loader.  */
+#if defined _ARCH_PWR5X && !defined(IS_IN_rtld) && defined(IN_LIB)
+#define SAVE_PPR \
+  mfspr r0,896;			\
+  std   r0,PPR_OFFSET(r13);
+#define RESTORE_PPR \
+  ld    r0,PPR_OFFSET(r13);	\
+  mtspr 896,r0;
+#else
+#define SAVE_PPR
+#define RESTORE_PPR
+#endif
+
 #define DO_CALL(syscall) \
-    li 0,syscall; \
-    sc
+  SAVE_PPR			\
+  li r0,syscall;		\
+  sc;				\
+  RESTORE_PPR
 
 /* ppc64 is always PIC */
 #undef JUMPTARGET
diff --git a/sysdeps/powerpc/sys/platform/ppc.h b/sysdeps/powerpc/sys/platform/ppc.h
index 165652c..79ad30a 100644
--- a/sysdeps/powerpc/sys/platform/ppc.h
+++ b/sysdeps/powerpc/sys/platform/ppc.h
@@ -44,4 +44,35 @@ __ppc_get_timebase (void)
 #endif  /* not __powerpc64__ */
 }
 
+
+/*
+ * ISA 2.05 and beyond support the Program Priority Register (PPR) to adjust
+ * thread priorities based on lock acquisition, wait and release. The ISA
+ * defines the use of form 'or Rx,Rx,Rx' as the way to modify the PRI field.
+ * The unprivileged priorities are:
+ *   Rx = 1 (low)
+ *   Rx = 2 (medium)
+ *   Rx = 6 (medium-low/normal)
+ * The 'or' instruction form is a nop in previous hardware, so it is safe to
+ * use unguarded. The default value is 'medium'.
+ */
+
+static inline void
+__ppc_set_ppr_med (void)
+{
+  __asm volatile ("or 2,2,2\n");
+}
+
+static inline void
+__ppc_set_ppr_med_low (void)
+{
+  __asm volatile ("or 6,6,6\n");
+}
+
+static inline void
+__ppc_set_ppr_low (void)
+{
+  __asm volatile ("or 1,1,1\n");
+}
+
 #endif  /* sys/platform/ppc.h */
diff --git a/sysdeps/powerpc/test-saveppr.c b/sysdeps/powerpc/test-saveppr.c
new file mode 100644
index 0000000..65a111e
--- /dev/null
+++ b/sysdeps/powerpc/test-saveppr.c
@@ -0,0 +1,106 @@
+/* Test for PPR register save/restore on syscalls.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <sys/platform/ppc.h>
+
+static inline uint64_t
+__ppc_get_ppr (void)
+{
+#ifdef __powerpc64__
+  uint64_t __ppr;
+  __asm__ volatile ("mfspr %0,896" : "=r" (__ppr));
+  return __ppr;
+#else
+  uint32_t __ppru, __pprl, __ppr;
+  __asm__ volatile ("mfspr  %0,896\n"
+		    "andi.  %2,%0,0xffff\n"
+		    "andis. %1,%0,0xffff\n"
+		    "or     %1,%1,%2\n"
+		    "sradi  %0,%0,32"
+		    : "=r" (__pprl), "=r" (__ppru), "=r" (__ppr)
+		    : : "cr0");
+  return (((uint64_t) __ppru << 32) | __pprl);
+#endif
+}
+
+static int
+do_test (void)
+{
+  uint64_t medlow_ppr_after, medlow_ppr_before;
+  uint64_t med_ppr_after, med_ppr_before;
+  uint64_t low_ppr_after, low_ppr_before;
+  int ret1, ret2, ret3, ret4;
+
+  /* First test: check if internal syscalls (using INTERNAL_SYSCALL_NCS
+     macro at sysdep.h) sets and restore the PPR register correctly.  */
+
+  __ppc_set_ppr_med_low();
+  medlow_ppr_before = __ppc_get_ppr ();
+  /* printf calls write (...)  */
+  printf ("PPR (med low) before = %016" PRIX64 "\n", medlow_ppr_before);
+  medlow_ppr_after = __ppc_get_ppr ();
+  printf ("PPR (med low) after  = %016" PRIX64 "\n", medlow_ppr_after);
+
+  ret1 = !(medlow_ppr_before == medlow_ppr_after);
+
+  /* Second test: check if the autogenerated syscalls also sets and restore
+     the PPR.  */
+
+  __ppc_set_ppr_low ();
+  low_ppr_before = __ppc_get_ppr ();
+  /* force a syscall  */
+  (void) getppid ();
+  low_ppr_after = __ppc_get_ppr ();
+
+  printf ("PPR (low) before     = %016" PRIX64 "\n", low_ppr_before);
+  printf ("PPR (low) after      = %016" PRIX64 "\n", low_ppr_after);
+
+  ret2 = !(low_ppr_before == low_ppr_after);
+
+  /* Finally testing with med PPR value  */
+  __ppc_set_ppr_med ();
+
+  med_ppr_before = __ppc_get_ppr ();
+  /* force a syscall again  */
+  (void) getppid ();
+  med_ppr_after = __ppc_get_ppr ();
+
+  printf ("PPR (med) before     = %016" PRIX64 "\n", med_ppr_before);
+  printf ("PPR (med) after      = %016" PRIX64 "\n", med_ppr_after);
+
+  ret3 = !(med_ppr_before == med_ppr_after);
+
+  __ppc_set_ppr_med_low();
+  medlow_ppr_before = __ppc_get_ppr ();
+  /* printf calls write (...)  */
+  printf ("PPR (med low) before = %016" PRIX64 "\n", medlow_ppr_before);
+  medlow_ppr_after = __ppc_get_ppr ();
+  printf ("PPR (med low) after  = %016" PRIX64 "\n", medlow_ppr_after);
+
+  ret4 = !(medlow_ppr_before == medlow_ppr_after);
+
+  return ret1 && ret2 && ret3 && ret4;
+}
+
+#define TEST_FUNCTION do_test ()
+
+#include "../../test-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/____longjmp_chk.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/____longjmp_chk.S
index 00313c3..5fedc3f 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/____longjmp_chk.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/____longjmp_chk.S
@@ -51,8 +51,10 @@
 	mr	r30,r4;					\
 	li	r3,0;					\
 	addi	r4,r1,8;				\
+	SAVE_PPR;					\
 	li	r0,__NR_sigaltstack;			\
 	sc;						\
+	RESTORE_PPR;					\
 	/* Without working sigaltstack we cannot perform the test.  */ \
 	bso	.Lok2;					\
 	lwz	r0,12(r1);				\
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext-common.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext-common.S
index 2942573..7c36c6d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext-common.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext-common.S
@@ -295,8 +295,10 @@ ENTRY(__CONTEXT_FUNC_NAME)
 
 4: /* L(do_sigret): */
 	addi	r1,r3,-0xd0
+	SAVE_PPR
 	li	r0,SYS_ify(rt_sigreturn)
 	sc
+	RESTORE_PPR
 	/* NOTREACHED */
 
 END (__CONTEXT_FUNC_NAME)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext-common.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext-common.S
index 90270b3..c8952cd 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext-common.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext-common.S
@@ -518,8 +518,10 @@ ENTRY(__CONTEXT_FUNC_NAME)
 
 4:/*L(do_sigret):*/
 	addi	r1,r4,-0xd0
+	SAVE_PPR
 	li	r0,SYS_ify(rt_sigreturn)
 	sc
+	RESTORE_PPR
 	/* NOTREACHED */
 
 END(__CONTEXT_FUNC_NAME)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
index b0fa372..097e580 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
@@ -20,6 +20,7 @@
 
 #include <sysdeps/unix/powerpc/sysdep.h>
 #include <tls.h>
+#include <tcb-offsets.h>
 
 /* Some systen calls got renamed over time, but retained the same semantics.
    Handle them here so they can be catched by both C and assembler stubs in
@@ -177,6 +178,21 @@
 # undef INTERNAL_SYSCALL_DECL
 # define INTERNAL_SYSCALL_DECL(err) long int err
 
+/* The Program Priority Register was added in ISA 2.03.  */
+#if defined _ARCH_PWR5X && !defined(IS_IN_rtld) && defined(IN_LIB)
+# define SETPPR_BEFORE							\
+  __asm__ (     							\
+    "mfspr 0,896\n"							\
+    "std 0,%0(2)" : : "i"(PPR_OFFSET) : "r0")
+# define SETPPR_AFTER							\
+  __asm__ (								\
+    "ld 0,%0(2)\n"							\
+    "mtspr 896,0\n" : : "i"(PPR_OFFSET) : "r0")
+#else
+# define SETPPR_BEFORE
+# define SETPPR_AFTER
+#endif
+
 # undef INTERNAL_SYSCALL
 # define INTERNAL_SYSCALL_NCS(name, err, nr, args...)			\
   ({									\
@@ -191,7 +207,8 @@
     register long int r10 __asm__ ("r10");				\
     register long int r11 __asm__ ("r11");				\
     register long int r12 __asm__ ("r12");				\
-    LOADARGS_##nr(name, args);					\
+    SETPPR_BEFORE;							\
+    LOADARGS_##nr(name, args);						\
     __asm__ __volatile__						\
       ("sc   \n\t"							\
        "mfcr %0"							\
@@ -201,6 +218,7 @@
        : ASM_INPUT_##nr							\
        : "cr0", "ctr", "memory");					\
     err = r0;								\
+    SETPPR_AFTER;							\
     (int) r3;								\
   })
 # define INTERNAL_SYSCALL(name, err, nr, args...) \
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/____longjmp_chk.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/____longjmp_chk.S
index 0715236..b9e140a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/____longjmp_chk.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/____longjmp_chk.S
@@ -42,8 +42,10 @@
 	cfi_offset (lr, 16);				\
 	li	r3,0;					\
 	addi	r4,r1,112;				\
+	SAVE_PPR;					\
 	li	r0,__NR_sigaltstack;			\
 	sc;						\
+	RESTORE_PPR;					\
 	/* Without working sigaltstack we cannot perform the test.  */ \
 	bso	.Lok2;					\
 	lwz	r0,112+8(r1);				\
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/setcontext.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/setcontext.S
index a7192a6..41911c0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/setcontext.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/setcontext.S
@@ -195,8 +195,10 @@ L(nv_error_exit):
      address in R3, so simply copy R3 to R1 before the syscall.  */
 L(nv_do_sigret):
   mr   r1,r3,
+  SAVE_PPR
   li   r0,SYS_ify(rt_sigreturn)
   sc
+  RESTORE_PPR
   /* No return.  */
 
 PSEUDO_END(__novec_setcontext)
@@ -469,8 +471,10 @@ L(error_exit):
      address in R3, so simply copy R3 to R1 before the syscall.  */
 L(do_sigret):
   mr   r1,r3,
+  SAVE_PPR
   li   r0,SYS_ify(rt_sigreturn)
   sc
+  RESTORE_PPR
   /* No return.  */
 
 PSEUDO_END(__setcontext)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/swapcontext.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/swapcontext.S
index f20e9a9..f452da8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/swapcontext.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/swapcontext.S
@@ -289,8 +289,10 @@ L(nv_error_exit):
      address in R3, so simply copy R3 to R1 before the syscall.  */
 L(nv_do_sigret):
   mr   r1,r3,
+  SAVE_PPR
   li   r0,SYS_ify(rt_sigreturn)
   sc
+  RESTORE_PPR
   /* No return.  */
 
 PSEUDO_END(__novec_swapcontext)
@@ -768,8 +770,10 @@ L(error_exit):
      address in R3, so simply copy R3 to R1 before the syscall.  */
 L(do_sigret):
   mr   r1,r3,
+  SAVE_PPR
   li   r0,SYS_ify(rt_sigreturn)
   sc
+  RESTORE_PPR
   /* No return.  */
 
 PSEUDO_END(__swapcontext)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
index 9b0693a..f41a9d6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
@@ -23,6 +23,7 @@
 
 #include <sysdeps/unix/powerpc/sysdep.h>
 #include <tls.h>
+#include <tcb-offsets.h>
 
 /* Define __set_errno() for INLINE_SYSCALL macro below.  */
 #ifndef __ASSEMBLER__
@@ -190,6 +191,20 @@
    gave back in the non-error (CR0.SO cleared) case, otherwise (CR0.SO set)
    the negation of the return value in the kernel gets reverted.  */
 
+#if defined _ARCH_PWR5X && !defined(IS_IN_rtld) && defined(IN_LIB)
+# define SETPPR_BEFORE							\
+  __asm__ (								\
+    "mfspr 0,896\n"							\
+    "std 0,%0(13)" : : "i"(PPR_OFFSET) : "r0", "cr5")
+# define SETPPR_AFTER							\
+  __asm__ (								\
+    "ld 0,%0(13)\n"							\
+    "mtspr 896,0" : : "i"(PPR_OFFSET) : "r0", "cr5")
+#else
+# define SETPPR_BEFORE
+# define SETPPR_AFTER
+#endif
+
 #undef INTERNAL_SYSCALL
 #define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
   ({									\
@@ -200,6 +215,7 @@
     register long int r6  __asm__ ("r6");				\
     register long int r7  __asm__ ("r7");				\
     register long int r8  __asm__ ("r8");				\
+    SETPPR_BEFORE;							\
     LOADARGS_##nr (name, ##args);					\
     __asm__ __volatile__						\
       ("sc\n\t"								\
@@ -211,8 +227,9 @@
        : ASM_INPUT_##nr							\
        : "r9", "r10", "r11", "r12",					\
          "cr0", "ctr", "memory");					\
-	  err = r0;  \
-    r3;  \
+    err = r0;								\
+    SETPPR_AFTER;							\
+    r3;									\
   })
 #define INTERNAL_SYSCALL(name, err, nr, args...)			\
   INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, args)
diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall.S b/sysdeps/unix/sysv/linux/powerpc/syscall.S
index 880c05b..ace6284 100644
--- a/sysdeps/unix/sysv/linux/powerpc/syscall.S
+++ b/sysdeps/unix/sysv/linux/powerpc/syscall.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1997, 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -18,6 +18,7 @@
 #include <sysdep.h>
 
 ENTRY (syscall)
+	SAVE_PPR
 	mr   r0,r3
 	mr   r3,r4
 	mr   r4,r5
@@ -26,5 +27,6 @@ ENTRY (syscall)
 	mr   r7,r8
 	mr   r8,r9
 	sc
+	RESTORE_PPR
 	PSEUDO_RET
 PSEUDO_END (syscall)
-- 
1.7.1


-- 
Adhemerval Zanella Netto
  Software Engineer
  Linux Technology Center Brazil
  Toolchain / GLIBC on Power Architecture
  azanella@linux.vnet.ibm.com / azanella@br.ibm.com
  +55 61 8642-9890


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]