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] RFC: PowerPC: Add Program Priority Register support


This patch adds save/restore for the Priority Program Register (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.

Although a program can easily set its priority using the 'or %1,%1,%1' the kernel
does not save neither restore its value on syscalls. This patch addresses this
limitation.

--

2012-02-27  Adhemerval Zanella  <azanella@linux.vnet.ibm.com>

	* elf/stackguard-macros.h: Updated stack_guard offset value.
	* nptl/sysdeps/powerpc/tls.h: Added PPR value to TCB.
	* sysdeps/unix/sysv/linux/powerpc/Makefile: Added sys/platform.h install.
	* nptl/sysdeps/powerpc/tcb-offsets.sym: Calculating PPR offset on TCB.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h: Added PPR support
	for ISA 2.03+.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/syscall.S: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/sys/platform.h: New file: platform
	specific macros for PPR set.
	* sysdeps/unix/sysv/linux/powerpc/Makefile: Added tst-saveppr test.
	* sysdeps/unix/sysv/linux/powerpc/tst-saveppr.c: New file: test if PPR is
	set/retored in syscalls.


diff --git a/elf/stackguard-macros.h b/elf/stackguard-macros.h
index a9889cf..5763870 100644
--- a/elf/stackguard-macros.h
+++ b/elf/stackguard-macros.h
@@ -11,7 +11,7 @@
   ({ uintptr_t x; asm ("ld %0,-28688(13)" : "=r" (x)); x; })
 #elif defined __powerpc__
 # define STACK_CHK_GUARD \
-  ({ uintptr_t x; asm ("lwz %0,-28680(2)" : "=r" (x)); x; })
+  ({ uintptr_t x; asm ("lwz %0,-28684(2)" : "=r" (x)); x; })
 #elif defined __sparc__ && defined __arch64__
 # define STACK_CHK_GUARD \
   ({ uintptr_t x; asm ("ldx [%%g7+0x28], %0" : "=r" (x)); x; })
diff --git a/nptl/sysdeps/powerpc/tcb-offsets.sym b/nptl/sysdeps/powerpc/tcb-offsets.sym
index 8ac133d..3f65249 100644
--- a/nptl/sysdeps/powerpc/tcb-offsets.sym
+++ b/nptl/sysdeps/powerpc/tcb-offsets.sym
@@ -14,7 +14,9 @@ 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)
 #endif
+
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/unix/sysv/linux/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile
index 55311a4..101eaba 100644
--- a/sysdeps/unix/sysv/linux/powerpc/Makefile
+++ b/sysdeps/unix/sysv/linux/powerpc/Makefile
@@ -4,6 +4,8 @@ syscall-list-32bit-condition := __WORDSIZE == 32
 syscall-list-64bit-options := -D__powerpc64__
 syscall-list-64bit-condition := __WORDSIZE == 64
 
+sysdep_headers += sys/platform.h
+
 ifeq ($(subdir),rt)
 librt-routines += rt-sysdep
 endif
@@ -15,3 +17,7 @@ endif
 ifeq ($(subdir),elf)
 sysdep_routines += dl-vdso
 endif
+
+ifeq ($(subdir),nptl)
+tests += tst-saveppr
+endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
index b0fa372..b10df5d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1992,1997-2006,2012 Free Software Foundation, Inc.
+/* Copyright (C) 1992-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
@@ -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,30 @@
 # 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
+# define SETPPR_BEFORE							\
+  __asm__ __volatile__(     						\
+    "cmpdi cr5,2,0\n\t"							\
+    "beq- cr5,12\n\t"							\
+    "mfspr 0,896\n\t"							\
+    "std 0,%[ppr](2)\n\t" : : [ppr]"i"(PPR_OFFSET) : "r0", "cr5")
+# define SETPPR_AFTER							\
+    "cmpdi cr5,2,0\n\t"							\
+    "beq- cr5,12\n\t"							\
+    "ld 0,%[ppr](2)\n\t"						\
+    "mtspr 896,0\n\t"
+# define SETPPR_INPUT							\
+    , [ppr]"i"(PPR_OFFSET)
+# define SETPPR_CLOBREG							\
+    , "cr5"
+#else
+# define SETPPR_BEFORE
+# define SETPPR_AFTER
+# define SETPPR_INPUT
+# define SETPPR_CLOBREG
+#endif
+
 # undef INTERNAL_SYSCALL
 # define INTERNAL_SYSCALL_NCS(name, err, nr, args...)			\
   ({									\
@@ -191,15 +216,17 @@
     register long int r10 __asm__ ("r10");				\
     register long int r11 __asm__ ("r11");				\
     register long int r12 __asm__ ("r12");				\
+    SETPPR_BEFORE;							\
     LOADARGS_##nr(name, args);					\
     __asm__ __volatile__						\
       ("sc   \n\t"							\
+       SETPPR_AFTER							\
        "mfcr %0"							\
        : "=&r" (r0),							\
 	 "=&r" (r3), "=&r" (r4), "=&r" (r5),  "=&r" (r6),  "=&r" (r7),	\
 	 "=&r" (r8), "=&r" (r9), "=&r" (r10), "=&r" (r11), "=&r" (r12)	\
-       : ASM_INPUT_##nr							\
-       : "cr0", "ctr", "memory");					\
+       : ASM_INPUT_##nr SETPPR_INPUT					\
+       : "cr0", "ctr", "memory" SETPPR_CLOBREG);			\
     err = r0;								\
     (int) r3;								\
   })
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
index 0f4fe53..73cb00a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h
@@ -1,5 +1,4 @@
-/* Copyright (C) 1992,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2012
-	Free Software Foundation, Inc.
+/* Copyright (C) 1992-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
@@ -23,6 +22,7 @@
 
 #include <sysdeps/unix/powerpc/sysdep.h>
 #include <tls.h>
+#include <tcb-offsets.h>
 
 /* Define __set_errno() for INLINE_SYSCALL macro below.  */
 #ifndef __ASSEMBLER__
@@ -192,6 +192,29 @@
    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
+# define SETPPR_BEFORE							\
+  __asm__ __volatile__(							\
+    "cmpdi cr5,13,0\n\t"						\
+    "beq- cr5,12\n\t"							\
+    "mfspr 0,896\n\t"							\
+    "std 0,%[ppr](13)\n\t" : : [ppr]"i"(PPR_OFFSET) : "r0", "cr5")
+# define SETPPR_AFTER							\
+    "cmpdi cr5,13,0\n\t"						\
+    "beq- cr5,12\n\t"							\
+    "ld 0,%[ppr](13)\n\t"						\
+    "mtspr 896,0\n\t"
+# define SETPPR_INPUT							\
+    ,[ppr]"i"(PPR_OFFSET)
+# define SETPPR_CLOBREG							\
+    ,"cr5"
+#else
+# define SETPPR_BEFORE
+# define SETPPR_AFTER
+# define SETPPR_INPUT
+# define SETPPR_CLOBREG
+#endif
+
 #undef INTERNAL_SYSCALL
 #define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
   ({									\
@@ -202,17 +225,19 @@
     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"								\
+       SETPPR_AFTER							\
        "mfcr  %0\n\t"							\
        "0:"								\
        : "=&r" (r0),							\
          "=&r" (r3), "=&r" (r4), "=&r" (r5),				\
          "=&r" (r6), "=&r" (r7), "=&r" (r8)				\
-       : ASM_INPUT_##nr							\
+       : ASM_INPUT_##nr	SETPPR_INPUT					\
        : "r9", "r10", "r11", "r12",					\
-         "cr0", "ctr", "memory");					\
+         "cr0", "ctr", "memory" SETPPR_CLOBREG);			\
 	  err = r0;  \
     r3;  \
   })
diff --git a/sysdeps/unix/sysv/linux/powerpc/sys/platform.h b/sysdeps/unix/sysv/linux/powerpc/sys/platform.h
new file mode 100644
index 0000000..52e6bf3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/sys/platform.h
@@ -0,0 +1,47 @@
+/* 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file contains platform specific macros and function definitions */
+
+#ifndef _PLATFORM_H
+#define _PLATFORM_H	1
+
+/*
+ * ISA 2.05 and beyond support the Program Priority Register (PPR) to adjust
+ * the 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 priorities are defined as:
+ * Rx = 2 (medium), Rx = 6 (medium-low/normal), Rx = 1 (low)
+ * This 'or' instruction form is a nop in previous hardware, so it's safe to
+ * use unguarded.
+ */
+#define PPR_PRIO_MED() \
+   ({ \
+      __asm __volatile("or 2,2,2\n"); \
+   })
+#define PPR_PRIO_MED_LOW() \
+   ({ \
+      __asm __volatile("or 6,6,6\n"); \
+   })
+#define PPR_PRIO_LOW() \
+   ({ \
+      __asm __volatile("or 1,1,1\n"); \
+   })
+#define PPR_PRIO_NORMAL() \
+   PPR_PRIO_MED_LOW()
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall.S b/sysdeps/unix/sysv/linux/powerpc/syscall.S
index 880c05b..1563dd6 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,10 @@
 #include <sysdep.h>
 
 ENTRY (syscall)
+#if defined _ARCH_PWR5X 
+	mfspr r0,896
+	std  r0,PPR_OFFSET(r13)
+#endif
 	mr   r0,r3
 	mr   r3,r4
 	mr   r4,r5
@@ -26,5 +30,9 @@ ENTRY (syscall)
 	mr   r7,r8
 	mr   r8,r9
 	sc
+#if defined _ARCH_PWR5X
+	ld   r0,PPR_OFFSET(r13)
+	mtspr 896,r0
+#endif
 	PSEUDO_RET
 PSEUDO_END (syscall)
diff --git a/sysdeps/unix/sysv/linux/powerpc/tst-saveppr.c b/sysdeps/unix/sysv/linux/powerpc/tst-saveppr.c
new file mode 100644
index 0000000..d5e59f1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/tst-saveppr.c
@@ -0,0 +1,63 @@
+/* Test for saving and restoring the PPR register 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 <unistd.h>
+#include <sys/platform.h>
+
+/* This program works both on 32 bit and 64 bit environments,
+   so we read the 64 bit PPR value word by word.  */
+
+void
+get_ppr (unsigned int *low_word, unsigned int *high_word)
+{
+  unsigned int ppr, word1, word2;
+
+  asm ("mfspr  %0,896\n"
+       "andi.  %2,%0,0xffff\n"
+       "andis. %1,%0,0xffff\n"
+       "or     %1,%1,%2\n"
+       "sradi  %0,%0,32" : 
+       "=r" (word1), "=r" (word2), "=r" (ppr) : : "cr0");
+
+  *low_word = word1;
+  *high_word = word2;
+}
+
+static int
+do_test (void)
+{
+  unsigned int low_word_before, high_word_before;
+  unsigned int low_word_after, high_word_after;
+
+  PPR_PRIO_MED_LOW();
+
+  get_ppr (&low_word_before, &high_word_before);
+
+  // force a syscall
+  getpid();
+
+  get_ppr (&low_word_after, &high_word_after);
+
+  return !(low_word_before == low_word_after &&
+	   high_word_before == high_word_after);
+}
+
+#define TEST_FUNCTION do_test ()
+
+#include "../../../../../test-skeleton.c"
-- 
1.6.0.2


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