AltiVec register ptrace support

Kumar Gala kumar.gala at motorola.com
Sat Dec 8 07:57:21 EST 2001


I have two different patches to the ptrace mechanism to add support
for AltiVec registers.

linux-2.4.8-altivec-ptrace.patch:  Adds support similar to existing
mechanisms to get/set registers via PEEK/POKE calls extending the FPU
model.

linux-2.4.16-altivec-ptrace.patch: Adds support for new ptrace commands
that match sparc/x86 PTRACE_{GET,SET}*REGS.  These dump the full register
state in a single call.

Personally, I would like to see the PTRACE_{GET,SET}*REGS method adopted
for 2.4.x.  RedHat is trying to push out some GDB changes for AltiVec that
require closure on this matter.

I would then be willing to add support for getting/setting the
full GPR+ register state, and FPR+ register state for 2.5.x (will keeping
the existing support in place for GPRs+, and FPRs).  I would like to see
the PPC ptrace follow more what x86 and sparc are doing.  I would also
like to collect together the FPR state and VR state into new structs in
the thread state.  This would be similar to how x86 handles FPR and FPX.

There are some other aspects to this problem that should be fixed in
2.5.x.  However, before starting into that I would like to get closure on
the AltiVec ptrace support for 2.4.x.

thanks

- kumar

-------------- next part --------------
diff -urN linux-2.4.16/arch/ppc/kernel/ptrace.c linux-2.4.16-avecptrace/arch/ppc/kernel/ptrace.c
--- linux-2.4.16/arch/ppc/kernel/ptrace.c	Mon Nov 26 07:29:17 2001
+++ linux-2.4.16-avecptrace/arch/ppc/kernel/ptrace.c	Fri Dec  7 14:37:20 2001
@@ -71,6 +71,64 @@
 	return -EIO;
 }
 
+#ifdef CONFIG_ALTIVEC
+/*
+ * Get contents of AltiVec register state in task TASK
+ */
+static inline int get_vrregs(unsigned long *data, struct task_struct *task)
+{
+	int i, j;
+
+        /* copy AltiVec registers VR[0] .. VR[31] */
+	for (i = 0;  i < 32;  i++)
+        {
+           for (j = 0; j < 4; j++, data++) 
+           {
+	      __put_user(task->thread.vr[i].u[j], data);
+           }
+        }
+
+        /* copy VSCR */
+        for (i = 0; i < 4; i++, data++) 
+        {
+	   __put_user(task->thread.vscr.u[i], data);
+        }
+
+        /* copy VRSAVE */
+        __put_user(task->thread.vrsave, data);
+
+	return (0);
+}
+
+/*
+ * Write contents of AltiVec register state into task TASK.
+ */
+static inline int set_vrregs(struct task_struct *task, unsigned long* data)
+{
+	int i, j;
+
+        /* copy AltiVec registers VR[0] .. VR[31] */
+	for (i = 0;  i < 32;  i++)
+        {
+           for (j = 0; j < 4; j++, data++) 
+           {
+	      __get_user(task->thread.vr[i].u[j], data);
+           }
+        }
+
+        /* copy VSCR */
+        for (i = 0; i < 4; i++, data++) 
+        {
+	   __get_user(task->thread.vscr.u[i], data);
+        }
+
+        /* copy VRSAVE */
+        __get_user(task->thread.vrsave, data);
+
+	return (0);
+}
+#endif
+
 static inline void
 set_single_step(struct task_struct *task)
 {
@@ -258,7 +316,35 @@
 	case PTRACE_DETACH:
 		ret = ptrace_detach(child, data);
 		break;
+#ifdef CONFIG_ALTIVEC
+	case PTRACE_GETVRREGS: { /* Get the child altivec register state. */
+		if (!access_ok(VERIFY_WRITE, (unsigned long*)data,
+			       (sizeof(__vector128) * 33 + sizeof(unsigned long)))) {
+			ret = -EIO;
+			break;
+		}
+                if (child->thread.regs->msr & MSR_VEC) {
+                   giveup_altivec(child);
+                }
+		ret = get_vrregs((unsigned long*)data, child);
+		break;
+	}
 
+	case PTRACE_SETVRREGS: { /* Set the child altivec register state. */
+		if (!access_ok(VERIFY_READ, (unsigned long*)data,
+			       (sizeof(__vector128) * 33 + sizeof(unsigned long)))) {
+			ret = -EIO;
+			break;
+		}
+		/* this is to clear the MSR_VEC bit to force a reload of register
+		 * state from memory */
+                if (child->thread.regs->msr & MSR_VEC) {
+                   giveup_altivec(child);
+                }
+		ret = set_vrregs(child, (unsigned long*)data);
+		break;
+	}
+#endif
 	default:
 		ret = -EIO;
 		break;
diff -urN linux-2.4.16/include/asm-ppc/ptrace.h linux-2.4.16-avecptrace/include/asm-ppc/ptrace.h
--- linux-2.4.16/include/asm-ppc/ptrace.h	Mon May 21 17:02:06 2001
+++ linux-2.4.16-avecptrace/include/asm-ppc/ptrace.h	Fri Dec  7 14:37:40 2001
@@ -103,5 +103,9 @@
 #define PT_FPR31 (PT_FPR0 + 2*31)
 #define PT_FPSCR (PT_FPR0 + 2*32 + 1)
 
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETVRREGS          18
+#define PTRACE_SETVRREGS          19
+
 #endif
 
-------------- next part --------------
--- linux-2.4.8/arch/ppc/kernel/ptrace.c	Mon Jul 30 15:17:30 2001
+++ linux-2.4.8-ptrace/arch/ppc/kernel/ptrace.c	Wed Oct 24 14:26:55 2001
@@ -158,12 +158,23 @@
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 2;
+#ifdef CONFIG_ALTIVEC
+		if ((addr & 3) || index > PT_VRSAVE)
+			break;
+#else
 		if ((addr & 3) || index > PT_FPSCR)
 			break;
+#endif
 
 		if (index < PT_FPR0) {
 			tmp = get_reg(child, (int) index);
 		} else {
+#ifdef CONFIG_ALTIVEC
+			if (index >= PT_VR0 && index <= PT_VRSAVE) {
+				if (child->thread.regs->msr & MSR_VEC)
+					giveup_altivec(child);
+			} else
+#endif
 			if (child->thread.regs != NULL
 			    && child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
@@ -190,7 +201,11 @@
 		ret = -EIO;
 		/* convert to index and check */
 		index = (unsigned long) addr >> 2;
+#ifdef CONFIG_ALTIVEC
+		if ((addr & 3) || index > PT_VRSAVE)
+#else
 		if ((addr & 3) || index > PT_FPSCR)
+#endif
 			break;
 
 		if (index == PT_ORIG_R3)
@@ -198,6 +213,12 @@
 		if (index < PT_FPR0) {
 			ret = put_reg(child, index, data);
 		} else {
+#ifdef CONFIG_ALTIVEC
+			if (index >= PT_VR0 && index <= PT_VRSAVE) {
+				if (child->thread.regs->msr & MSR_VEC)
+					giveup_altivec(child);
+			}
+#endif
 			if (child->thread.regs != NULL
 			    && child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
--- linux-2.4.8/include/asm-ppc/ptrace.h	Mon Jul 30 12:41:17 2001
+++ linux-2.4.8-ptrace/include/asm-ppc/ptrace.h	Wed Oct 24 14:27:20 2001
@@ -103,5 +103,12 @@
 #define PT_FPR31 (PT_FPR0 + 2*31)
 #define PT_FPSCR (PT_FPR0 + 2*32 + 1)
 
+/* old end of PTRACE_PEEKUSR range */
+
+#define PT_VR0  (PT_FPSCR + 1)         /* this has value of 114, just beyond the fpscr. */
+#define PT_VR31 (PT_VR0 + 4*31)
+#define PT_VSCR (PT_VR0 + 4*32)                /* this has value of 248 */
+#define PT_VRSAVE (PT_VR0 + 4*33)      /* this has value of 252 */
+
 #endif
 


More information about the Linuxppc-dev mailing list