[parisc-linux] [patch] kernel-mode unaligned handler

Randolph Chung randolph@tausq.org
Tue, 2 Oct 2001 23:09:22 -0700


With some nudging and help from willy I looked into enabling kernel-mode
unaligned access handling.... the attached patch seems to work; if it
doesn't look wrong to anybody i'll check it in... :)

tested on a c3k running a 64-bit kernel... for kernel space I tried
"nmap -O localhost" and that works ok now.

Comments appreciated,
randolph
-- 
   @..@                                         http://www.TauSq.org/
  (----)
 ( >__< )
 ^^ ~~ ^^


Index: unaligned.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/unaligned.c,v
retrieving revision 1.7
diff -u -r1.7 unaligned.c
--- unaligned.c	2001/07/14 21:17:02	1.7
+++ unaligned.c	2001/10/03 06:00:11
@@ -129,8 +129,10 @@
 		regs->isr, regs->ior, toreg, len);
 
 	__asm__ __volatile__  (
+"       mfsp %%sr1, %%r20\n"
+"       mtsp %6, %%sr1\n"
 "	copy %%r0, %0\n"
-"0:	ldbs,ma	1(%%sr3, %4), %%r19\n"
+"0:	ldbs,ma	1(%%sr1,%4), %%r19\n"
 "	addi -1, %5, %5\n"
 "	cmpib,>= 0, %5, 2f\n"
 "	or %%r19, %0, %0\n"
@@ -143,8 +145,7 @@
 #endif
 	
 "1:	ldi	10, %1\n"
-"2:\n"
-
+"2:     mtsp %%r20, %%sr1\n"
 "	.section __ex_table,\"a\"\n"
 #ifdef __LP64__
 	".dword 0b, (1b-0b)\n"
@@ -153,8 +154,8 @@
 #endif
 	".previous\n" 
 	: "=r" (val), "=r" (ret)
-	: "0" (val), "1" (ret), "r" (saddr), "r" (len)
-	: "r19" );
+	: "0" (val), "1" (ret), "r" (saddr), "r" (len), "r" (regs->isr)
+	: "r19", "r20" );
 
 	DPRINTF("val = 0x" RFMT "\n", val);
 
@@ -184,12 +185,14 @@
 
 
 	__asm__ __volatile__ (
+"       mfsp %%sr1, %%r20\n"		/* save sr1 */
+"       mtsp %5, %%sr1\n"
 #ifdef __LP64__
 "0:	extrd,u %2, 7, 8, %%r19\n"
 #else
 "0:	extrw,u %2, 7, 8, %%r19\n"
 #endif
-"1:	stb,ma %%r19, 1(%%sr3, %3)\n"
+"1:	stb,ma %%r19, 1(%%sr1, %3)\n"
 "	addi -1, %4, %4\n"
 "	cmpib,>= 0, %4, 3f\n"
 	
@@ -203,7 +206,7 @@
 "	nop\n"
 
 "2:	ldi 11, %0\n"
-"3:\n"
+"3:     mtsp %%r20, %%sr1\n"
 "	.section __ex_table,\"a\"\n"
 #ifdef __LP64__
 	".dword 1b, (2b-1b)\n"
@@ -212,8 +215,8 @@
 #endif
 	".previous\n" 
 	: "=r" (ret)
-	: "0" (ret), "r" (val), "r" (regs->ior), "r" (len)
-	: "r19" );
+	: "0" (ret), "r" (val), "r" (regs->ior), "r" (len), "r" (regs->isr)
+	: "r19", "r20" );
 
 	return ret;
 }
@@ -233,7 +236,6 @@
 	 */
 	if (!user_mode(regs))
 	{
-#if 0 /* TODO: do we want to handle this? */
 		const struct exception_table_entry *fix;
 
 		/* see if the offending code have its own
@@ -257,25 +259,26 @@
 
 			return;
 		}
-#endif
-		die_if_kernel("Unaligned data reference", regs, 28);
 	}
 
 	/* log a message with pacing */
-	if (unaligned_count > 5 && jiffies - last_time > 5*HZ)
+	if (user_mode(regs))
 	{
-		unaligned_count = 0;
-		last_time = jiffies;
-	}
-	if (++unaligned_count < 5)
-	{
-		char buf[256];
-		sprintf(buf, "%s(%d): unaligned access to 0x" RFMT " at ip=0x" RFMT "\n",
-			current->comm, current->pid, regs->ior, regs->iaoq[0]);
-		printk(KERN_WARNING "%s", buf);
+		if (unaligned_count > 5 && jiffies - last_time > 5*HZ)
+		{
+			unaligned_count = 0;
+			last_time = jiffies;
+		}
+		if (++unaligned_count < 5)
+		{
+			char buf[256];
+			sprintf(buf, "%s(%d): unaligned access to 0x" RFMT " at ip=0x" RFMT "\n",
+				current->comm, current->pid, regs->ior, regs->iaoq[0]);
+			printk(KERN_WARNING "%s", buf);
 #ifdef DEBUG_UNALIGNED
-		show_regs(regs);
-#endif	
+			show_regs(regs);
+#endif		
+		}
 	}
 
 	/* TODO: make this cleaner... */
@@ -363,7 +366,9 @@
 
 	if (ret)
 	{
-		printk(KERN_CRIT "Unaligned handler failed, ret = %d ", ret);
+		printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
+		die_if_kernel("Unaligned data reference", regs, 28);
+
 		/* couldn't handle it ... */
 		si.si_signo = SIGBUS;
 		si.si_errno = 0;