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]

[PATCH] PowerPC: Add Program Priority Register support


Second spin of my previous Program Priority Register (PPR) support for
POWER. I narrow down the issues I was observing and added the set/restore
on all syscalls in glibc.

This patch adds save/restore for the PPR for ISA 2.03+ for POWER
machines. The PPR register is a special register that controls the
program priority. It is documented on latest ISA 2.06 (Book II,
Chapter 3.1) and it can be used to improve lock performance by setting
an higher priority on critical sections and an lower priority on lock
holding.

The kernel will save/restore the PPR on context switch in future versions,
so I intend to update the patch with guards for when it happens. I follow
previous sys/platform/ppc.h update by creating inline static functions for
POWER specific functions. I also used 'mtspr/mfspr' instead of 'mtppr'
because although the ISA 2.06 documents the mnemonic, binutils does not
implements it.

Tested on PPC32 and PPC64.

---

2012-08-14 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..95e06ae 100644
--- a/manual/platform.texi
+++ b/manual/platform.texi
@@ -26,3 +26,21 @@ 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.
+
+The @dfn{Program Prioriry Register} (PPR) is a 64-bit register that controls
+the program's priority. By adjusting the PPR value the programmer may
+improve the system throughput by causing the system resouces to be used
+more efficiently, especially in contention situations. 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..a1a5709 100644
--- a/sysdeps/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/powerpc/powerpc32/sysdep.h
@@ -89,9 +89,26 @@ GOT_LABEL:			;					      \
   cfi_endproc;								      \
   ASM_SIZE_DIRECTIVE(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.  */
+#if defined(_ARCH_PWR5X) && !defined(IS_IN_rtld) && defined(IN_LIB)
+#define SET_PPR \
+  mfspr r0,896;								      \
+  std   r0,PPR_OFFSET(r2);
+#define RESTORE_PPR \
+  ld    r0,PPR_OFFSET(r2);						      \
+  mtspr 896,r0;
+#else
+#define SET_PPR
+#define RESTORE_PPR
+#endif
+
 #define DO_CALL(syscall)						      \
+    SET_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..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.  */
+#if defined _ARCH_PWR5X && !defined(IS_IN_rtld) && defined(IN_LIB)
+#define SET_PPR	\
+  mfspr r0,896;			\
+  std   r0,PPR_OFFSET(r13);
+#define RESTORE_PPR \
+  ld    r0,PPR_OFFSET(r13);	\
+  mtspr 896,r0;
+#else
+#define SET_PPR
+#define RESTORE_PPR
+#endif
+
 #define DO_CALL(syscall) \
-    li 0,syscall; \
-    sc
+  SET_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..5752842 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.
+ */
+
+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..1b52cb4 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;				\
+	SET_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..2d3137c 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
+	SET_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..975813c 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
+	SET_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..7713751 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;				\
+	SET_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..790df2c 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,
+  SET_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,
+  SET_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..6971149 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,
+  SET_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,
+  SET_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..32a186a 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)
+	SET_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]