All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stef Simoens <stef.simoens@pi.be>
To: linuxppc-dev@lists.linuxppc.org
Subject: [PATCH] align.c
Date: Wed, 14 Jul 2004 20:36:05 +0200	[thread overview]
Message-ID: <40F57D15.8030700@pi.be> (raw)

[-- Attachment #1: Type: text/plain, Size: 221 bytes --]

This is an (updated) diff to arch/ppc/kernel/align.c of the 2.6.8-rc1
kernel.

The patch adds support for the handling of alignment exceptions of
multiple (lmw/stmw) and string (lswi/lswx/stswi/stswx) instructions.

Stef

[-- Attachment #2: linux-2.6.8-rc1-align.patch --]
[-- Type: text/plain, Size: 7107 bytes --]

diff -ur linux-2.6.8-rc1/arch/ppc/kernel/align.c linux-2.6.8-rc1-mq/arch/ppc/kernel/align.c
--- linux-2.6.8-rc1/arch/ppc/kernel/align.c	2004-07-12 17:46:42.525695737 +0200
+++ linux-2.6.8-rc1-mq/arch/ppc/kernel/align.c	2004-07-12 20:25:24.390989048 +0200
@@ -17,8 +17,8 @@
 #include <asm/cache.h>

 struct aligninfo {
-	unsigned char len;
-	unsigned char flags;
+	unsigned int len;
+	unsigned int flags;
 };

 #if defined(CONFIG_4xx) || defined(CONFIG_POWER4) || defined(CONFIG_BOOKE)
@@ -30,14 +30,16 @@

 #define INVALID	{ 0, 0 }

-#define LD	1	/* load */
-#define ST	2	/* store */
-#define	SE	4	/* sign-extend value */
-#define F	8	/* to/from fp regs */
-#define U	0x10	/* update index register */
-#define M	0x20	/* multiple load/store */
-#define S	0x40	/* single-precision fp, or byte-swap value */
-#define HARD	0x80	/* string, stwcx. */
+#define LD	0x001	/* load */
+#define ST	0x002	/* store */
+#define	SE	0x004	/* sign-extend value */
+#define F	0x008	/* to/from fp regs */
+#define U	0x010	/* update index register */
+#define M	0x020	/* multiple load/store */
+#define S	0x040	/* single-precision fp, or byte-swap value */
+#define STR_OP	0x080	/* string, length stored in instruction */
+#define STR_XER	0x100	/* string, length stored in XER[25-31] */
+#define HARD	0x200	/* too hard: stwcx. */

 #define DCBZ	0x5f	/* 8xx/82xx dcbz faults when cache not enabled */

@@ -88,10 +90,10 @@
 	INVALID,		/* 01 0 0101: lwax */
 	INVALID,		/* 01 0 0110 */
 	INVALID,		/* 01 0 0111 */
-	{ 0, LD+HARD },		/* 01 0 1000: lswx */
-	{ 0, LD+HARD },		/* 01 0 1001: lswi */
-	{ 0, ST+HARD },		/* 01 0 1010: stswx */
-	{ 0, ST+HARD },		/* 01 0 1011: stswi */
+	{ 4, LD+STR_XER },	/* 01 0 1000: lswx */
+	{ 4, LD+STR_OP },	/* 01 0 1001: lswi */
+	{ 4, ST+STR_XER },	/* 01 0 1010: stswx */
+	{ 4, ST+STR_OP },	/* 01 0 1011: stswi */
 	INVALID,		/* 01 0 1100 */
 	INVALID,		/* 01 0 1101 */
 	INVALID,		/* 01 0 1110 */
@@ -183,11 +185,11 @@
 int
 fix_alignment(struct pt_regs *regs)
 {
-	int instr, nb, flags;
+	int instr, nb, mb, mr, flags;
 #if defined(CONFIG_4xx) || defined(CONFIG_POWER4) || defined(CONFIG_BOOKE)
 	int opcode, f1, f2, f3;
 #endif
-	int i, t;
+	int i, j, t;
 	int reg, areg;
 	unsigned char __user *addr;
 	union {
@@ -195,7 +197,7 @@
 		float f;
 		double d;
 		unsigned char v[8];
-	} data;
+	} data[32];

 	CHECK_FULL_REGS(regs);

@@ -256,9 +259,34 @@

 	addr = (unsigned char __user *)regs->dar;

+	/* Get mb (total number of bytes to load)
+	   and mr (number of registers needed) if we're dealing with strings */
+	if (flags & M) {
+		mr = 32 - reg;
+		mb = nb * mr; /* nb = bytes per register */
+	} else if (flags & STR_OP) {
+		instr = *((unsigned int *)regs->nip);
+		mb = (instr >> 11) & 0x1f;
+		if (mb == 0)
+			mb = 32; /* mb = 32 if bits are 0 */
+		mr = mb / 4;
+		if ((mb % 4) > 0)
+			mr++;
+	} else if (flags & STR_XER) {
+		mb = regs->xer & 0x7f;
+		/* This shouldn't be 128 if XER[25-31] is 0,
+		   in that case it's actually a no-op */
+		mr = mb / 4;
+		if ((mb % 4) > 0)
+			mr++;
+	} else {
+		mb = nb;
+		mr = 1;
+	}
+
 	/* Verify the address of the operand */
 	if (user_mode(regs)) {
-		if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+		if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, mb))
 			return -EFAULT;	/* bad address */
 	}

@@ -268,57 +296,69 @@
 			giveup_fpu(current);
 		preempt_enable();
 	}
-	if (flags & M)
-		return 0;		/* too hard for now */

 	/* If we read the operand, copy it in */
 	if (flags & LD) {
-		if (nb == 2) {
-			data.v[0] = data.v[1] = 0;
-			if (__get_user(data.v[2], addr)
-			    || __get_user(data.v[3], addr+1))
-				return -EFAULT;
-		} else {
-			for (i = 0; i < nb; ++i)
-				if (__get_user(data.v[i], addr+i))
+		for (j = 0; j < mr; ++j) {
+			if (nb == 2) {
+				data[j].v[0] = data[j].v[1] = 0;
+				if (__get_user(data[j].v[2], addr)
+				    || __get_user(data[j].v[3], addr+1))
 					return -EFAULT;
+			} else {
+				for (i = 0; i < nb; ++i) {
+					if ((j*4)+i < mb) {
+						if (__get_user(data[j].v[i], addr+(j*4)+i))
+							return -EFAULT;
+					} else {
+						data[j].v[i] = 0;
+					}
+				}
+			}
 		}
 	}

-	switch (flags & ~U) {
+	/* We already did the main work for the multiple register cases
+	   (M, STR_OP and STR_XER), so they get filtered out. As the only
+	   possible combinations with multiples are with LD and ST, there
+	   is only a loop there. data[0] is used when there is only one
+	   register involved. */
+	switch (flags & ~(U|M|STR_OP|STR_XER)) {
 	case LD+SE:
-		if (data.v[2] >= 0x80)
-			data.v[0] = data.v[1] = -1;
+		if (data[0].v[2] >= 0x80)
+			data[0].v[0] = data[0].v[1] = -1;
 		/* fall through */
 	case LD:
-		regs->gpr[reg] = data.l;
+		for (i = 0; i < mr; ++i)
+			regs->gpr[reg+i] = data[i].l;
 		break;
 	case LD+S:
 		if (nb == 2) {
-			SWAP(data.v[2], data.v[3]);
+			SWAP(data[0].v[2], data[0].v[3]);
 		} else {
-			SWAP(data.v[0], data.v[3]);
-			SWAP(data.v[1], data.v[2]);
+			SWAP(data[0].v[0], data[0].v[3]);
+			SWAP(data[0].v[1], data[0].v[2]);
 		}
-		regs->gpr[reg] = data.l;
+		regs->gpr[reg] = data[0].l;
 		break;
 	case ST:
-		data.l = regs->gpr[reg];
+		for (i = 0; i < mr; ++i)
+			data[i].l = regs->gpr[reg+i];
 		break;
 	case ST+S:
-		data.l = regs->gpr[reg];
+		data[0].l = regs->gpr[reg];
 		if (nb == 2) {
-			SWAP(data.v[2], data.v[3]);
+			SWAP(data[0].v[2], data[0].v[3]);
 		} else {
-			SWAP(data.v[0], data.v[3]);
-			SWAP(data.v[1], data.v[2]);
+			SWAP(data[0].v[0], data[0].v[3]);
+			SWAP(data[0].v[1], data[0].v[2]);
 		}
 		break;
 	case LD+F:
-		current->thread.fpr[reg] = data.d;
+		current->thread.fpr[reg] = data[0].d;
 		break;
 	case ST+F:
-		data.d = current->thread.fpr[reg];
+		data[0].d = current->thread.fpr[reg];
 		break;
 	/* these require some floating point conversions... */
 	/* we'd like to use the assignment, but we have to compile
@@ -327,15 +367,15 @@
 	case LD+F+S:
 		preempt_disable();
 		enable_kernel_fp();
-		cvt_fd(&data.f, &current->thread.fpr[reg], &current->thread.fpscr);
-		/* current->thread.fpr[reg] = data.f; */
+		cvt_fd(&data[0].f, &current->thread.fpr[reg], &current->thread.fpscr);
+		/* current->thread.fpr[reg] = data[0].f; */
 		preempt_enable();
 		break;
 	case ST+F+S:
 		preempt_disable();
 		enable_kernel_fp();
-		cvt_df(&current->thread.fpr[reg], &data.f, &current->thread.fpscr);
-		/* data.f = current->thread.fpr[reg]; */
+		cvt_df(&current->thread.fpr[reg], &data[0].f, &current->thread.fpscr);
+		/* data[0].f = current->thread.fpr[reg]; */
 		preempt_enable();
 		break;
 	default:
@@ -344,14 +384,16 @@
 	}

 	if (flags & ST) {
-		if (nb == 2) {
-			if (__put_user(data.v[2], addr)
-			    || __put_user(data.v[3], addr+1))
-				return -EFAULT;
-		} else {
-			for (i = 0; i < nb; ++i)
-				if (__put_user(data.v[i], addr+i))
+		for (j = 0; j < mr; ++j) {
+			if (nb == 2) {
+				if (__put_user(data[j].v[2], addr)
+				    || __put_user(data[j].v[3], addr+1))
 					return -EFAULT;
+			} else {
+				for (i = 0; (i < nb) && (((j*4)+i) < mb); ++i)
+					if (__put_user(data[j].v[i], addr+(j*4)+i))
+						return -EFAULT;
+			}
 		}
 	}


             reply	other threads:[~2004-07-14 18:36 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-07-14 18:36 Stef Simoens [this message]
2004-07-15 14:15 ` [PATCH] align.c Kumar Gala
2004-07-16 17:42   ` Stef Simoens
2004-07-22 22:49     ` Kumar Gala
2004-07-23 13:10       ` Segher Boessenkool
2004-08-03  8:00     ` Gabriel Paubert
2004-08-04 11:36       ` Segher Boessenkool

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=40F57D15.8030700@pi.be \
    --to=stef.simoens@pi.be \
    --cc=linuxppc-dev@lists.linuxppc.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.