This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
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