[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-arm-kernel
Subject:    [RFC] thumb user mode alignment fault handling
From:       "George G. Davis" <davis_g () comcast ! net>
Date:       2004-07-29 4:47:25
Message-ID: 20040729044725.GF28650 () mvista ! com
[Download RAW message or body]

Greetings,

Ok, no nibbles on my last post on this subject, so here's a first quick
stab at implementing support for thumb user mode alignment fault fixups...

I've adapted the gdb/sim/arm/thumbemu.c for use in the kernel in order
to add support for thumb user mode alignment fixups. It merely translates
Thumb instructions into equivalent ARM instructions. In our case, we only
care about Thumb ld/st instruction forms since those are the only forms
which may cause an alignment fault. So I've simplified the original
gdb/sim/arm/thumbemu.c by eliminating support for all non-ld/st Thumb
instruction forms. Now, when an alignment fault occurs, we use thumbemu.c
to translate Thumb ld/st instructions into ARM equivalents and the kernel
alignment fault handler works as usual for those Thumb ld/st instructions.
See Documentation/arm/mem_alignment. Of course, it also works as before
for the non-Thumb mode case (or at least as well as it ever did before : ).

This all seems to work based on a quick initial test but this needs a
_lot_ more testing. I also need to review the ARM ARM to verify that we've
got all Thumb ld/st instruction forms covered, clean up thumbemu.c and
finally incorporate what remains of thumbemu.c into arch/arm/mm/aligment.c.

This is not intended to be a final solution but is merely a work-in-progress
with some crufty ugly formatting and/or debug code whilst I whittle away at
it.

BTW, does anyone know of a good test suite for testing non-aligned transfers?
Alas, I'll probably need to write one in assembler anyway to insure that all
Thumb ld/st instruction variants are tested. But any recommendations for
non-aligned transfer test suites would be appreciated.

Comment are appreciated. TIA!

--
Regards,
George

["patch-2.6.7-thumb_alignment_fixup" (text/plain)]

Index: linux-2.6.7/arch/arm/mm/Makefile
===================================================================
--- linux-2.6.7.orig/arch/arm/mm/Makefile	2004-06-16 05:20:26.000000000 +0000
+++ linux-2.6.7/arch/arm/mm/Makefile	2004-07-28 20:55:21.000000000 +0000
@@ -8,6 +8,7 @@
 obj-$(CONFIG_MODULES)		+= proc-syms.o
 
 obj-$(CONFIG_ALIGNMENT_TRAP)	+= alignment.o
+obj-$(CONFIG_ALIGNMENT_TRAP)	+= thumbemu.o
 obj-$(CONFIG_DISCONTIGMEM)	+= discontig.o
 
 obj-$(CONFIG_CPU_ABRT_EV4)	+= abort-ev4.o
Index: linux-2.6.7/arch/arm/mm/alignment.c
===================================================================
--- linux-2.6.7.orig/arch/arm/mm/alignment.c	2004-07-27 18:38:24.000000000 +0000
+++ linux-2.6.7/arch/arm/mm/alignment.c	2004-07-29 01:59:01.000000000 +0000
@@ -368,7 +368,7 @@
 	if (LDM_S_BIT(instr))
 		goto bad;
 
-	correction = 4; /* processor implementation defined */
+	correction = thumb_mode(regs) ? 2 : 4; /* processor implementation defined */
 	regs->ARM_pc += correction;
 
 	ai_multi += 1;
@@ -456,8 +456,14 @@
 	unsigned long instr, instrptr;
 	int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
 	unsigned int type;
+	u16 tinstr;
 
 	instrptr = instruction_pointer(regs);
+	if (unlikely(thumb_mode(regs))) {
+		extern void ARMul_ThumbDecode(struct pt_regs *, u16, unsigned long *);
+		tinstr = *(u16 *)(instrptr & ~1);
+		ARMul_ThumbDecode(regs, tinstr, &instr);
+	} else
 	instr = *(unsigned long *)instrptr;
 
 	if (user_mode(regs))
@@ -467,7 +473,7 @@
 
  fixup:
 
-	regs->ARM_pc += 4;
+	regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
 
 	switch (CODING_BITS(instr)) {
 	case 0x00000000:	/* ldrh or strh */
@@ -537,7 +543,7 @@
  bad_or_fault:
 	if (type == TYPE_ERROR)
 		goto bad;
-	regs->ARM_pc -= 4;
+	regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
 	/*
 	 * We got a fault - fix it up, or die.
 	 */
@@ -557,9 +563,17 @@
 	ai_user += 1;
 
 	if (ai_usermode & 1)
+	{
+		if (thumb_mode(regs)) {
+		printk("Alignment trap: %s (%d) PC=0x%08lxT Instr=0x%04x "
+		       "Address=0x%08lx FSR 0x%03x\n", current->comm,
+			current->pid, instrptr, tinstr, addr, fsr);
+		} else {
 		printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%08lx "
 		       "Address=0x%08lx FSR 0x%03x\n", current->comm,
 			current->pid, instrptr, instr, addr, fsr);
+		}
+	}
 
 	if (ai_usermode & 2)
 		goto fixup;
Index: linux-2.6.7/arch/arm/mm/thumbemu.c
===================================================================
--- linux-2.6.7.orig/arch/arm/mm/thumbemu.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.7/arch/arm/mm/thumbemu.c	2004-07-29 02:16:08.000000000 +0000
@@ -0,0 +1,144 @@
+/*  thumbemu.c -- Thumb instruction emulation.
+    Copyright (C) 1996, Cygnus Software Technologies Ltd.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+ 
+    This program 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 General Public License for more details.
+ 
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* We can provide simple Thumb simulation by decoding the Thumb
+instruction into its corresponding ARM instruction, and using the
+existing ARM simulator.  */
+
+#include <linux/ptrace.h>
+
+/* Decode a 16bit Thumb instruction.  The instruction is in the low
+   16-bits of the tinstr field, with the following Thumb instruction
+   held in the high 16-bits.  Passing in two Thumb instructions allows
+   easier simulation of the special dual BL instruction.  */
+
+void ARMul_ThumbDecode (struct pt_regs *state, u16 tinstr, unsigned long *ainstr)
+{
+#if 1				/* debugging to catch non updates */
+  *ainstr = 0xdeadc0de;
+#endif
+
+  switch ((tinstr & 0xF800) >> 11)
+    {
+    case 9:			/* LDR Rd,[PC,#imm8] */
+      /* Format 6 */
+      *ainstr = 0xE59F0000	/* base */
+	| ((tinstr & 0x0700) << (12 - 8))	/* Rd */
+	| ((tinstr & 0x00FF) << (2 - 0));	/* off8 */
+      break;
+    case 10:
+    case 11:
+      /* TODO: Format 7 and Format 8 perform the same ARM encoding, so
+         the following could be merged into a single subset, saving on
+         the following boolean: */
+      if ((tinstr & (1 << 9)) == 0)
+	{
+	  /* Format 7 */
+	  static const u32 subset[4] = {
+	    0xE7800000,		/* STR  Rd,[Rb,Ro] */
+	    0xE7C00000,		/* STRB Rd,[Rb,Ro] */
+	    0xE7900000,		/* LDR  Rd,[Rb,Ro] */
+	    0xE7D00000		/* LDRB Rd,[Rb,Ro] */
+	  };
+	  *ainstr = subset[(tinstr & 0x0C00) >> 10]	/* base */
+	    | ((tinstr & 0x0007) << (12 - 0))	/* Rd */
+	    | ((tinstr & 0x0038) << (16 - 3))	/* Rb */
+	    | ((tinstr & 0x01C0) >> 6);	/* Ro */
+	}
+      else
+	{
+	  /* Format 8 */
+	  static const u32 subset[4] = {
+	    0xE18000B0,		/* STRH  Rd,[Rb,Ro] */
+	    0xE19000D0,		/* LDRSB Rd,[Rb,Ro] */
+	    0xE19000B0,		/* LDRH  Rd,[Rb,Ro] */
+	    0xE19000F0		/* LDRSH Rd,[Rb,Ro] */
+	  };
+	  *ainstr = subset[(tinstr & 0x0C00) >> 10]	/* base */
+	    | ((tinstr & 0x0007) << (12 - 0))	/* Rd */
+	    | ((tinstr & 0x0038) << (16 - 3))	/* Rb */
+	    | ((tinstr & 0x01C0) >> 6);	/* Ro */
+	}
+      break;
+    case 12:			/* STR Rd,[Rb,#imm5] */
+    case 13:			/* LDR Rd,[Rb,#imm5] */
+    case 14:			/* STRB Rd,[Rb,#imm5] */
+    case 15:			/* LDRB Rd,[Rb,#imm5] */
+      /* Format 9 */
+      {
+	static const u32 subset[4] = {
+	  0xE5800000,		/* STR  Rd,[Rb,#imm5] */
+	  0xE5900000,		/* LDR  Rd,[Rb,#imm5] */
+	  0xE5C00000,		/* STRB Rd,[Rb,#imm5] */
+	  0xE5D00000		/* LDRB Rd,[Rb,#imm5] */
+	};
+	/* The offset range defends on whether we are transferring a
+	   byte or word value: */
+	*ainstr = subset[(tinstr & 0x1800) >> 11]	/* base */
+	  | ((tinstr & 0x0007) << (12 - 0))	/* Rd */
+	  | ((tinstr & 0x0038) << (16 - 3))	/* Rb */
+	  | ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2)));	/* off5 */
+      }
+      break;
+    case 16:			/* STRH Rd,[Rb,#imm5] */
+    case 17:			/* LDRH Rd,[Rb,#imm5] */
+      /* Format 10 */
+      *ainstr = ((tinstr & (1 << 11))	/* base */
+		 ? 0xE1D000B0	/* LDRH */
+		 : 0xE1C000B0)	/* STRH */
+	| ((tinstr & 0x0007) << (12 - 0))	/* Rd */
+	| ((tinstr & 0x0038) << (16 - 3))	/* Rb */
+	| ((tinstr & 0x01C0) >> (6 - 1))	/* off5, low nibble */
+	| ((tinstr & 0x0600) >> (9 - 8));	/* off5, high nibble */
+      break;
+    case 18:			/* STR Rd,[SP,#imm8] */
+    case 19:			/* LDR Rd,[SP,#imm8] */
+      /* Format 11 */
+      *ainstr = ((tinstr & (1 << 11))	/* base */
+		 ? 0xE59D0000	/* LDR */
+		 : 0xE58D0000)	/* STR */
+	| ((tinstr & 0x0700) << (12 - 8))	/* Rd */
+	| ((tinstr & 0x00FF) << 2);	/* off8 */
+      break;
+    case 22:
+    case 23:
+	{
+	  /* Format 14 */
+	  static const u32 subset[4] = {
+	    0xE92D0000,		/* STMDB sp!,{rlist}    */
+	    0xE92D4000,		/* STMDB sp!,{rlist,lr} */
+	    0xE8BD0000,		/* LDMIA sp!,{rlist}    */
+	    0xE8BD8000		/* LDMIA sp!,{rlist,pc} */
+	  };
+	  *ainstr = subset[((tinstr & (1 << 11)) >> 10)
+			   | ((tinstr & (1 << 8)) >> 8)]	/* base */
+	    | (tinstr & 0x00FF);	/* mask8 */
+	}
+      break;
+    case 24:			/* STMIA */
+    case 25:			/* LDMIA */
+      /* Format 15 */
+      *ainstr = ((tinstr & (1 << 11))	/* base */
+		 ? 0xE8B00000	/* LDMIA */
+		 : 0xE8A00000)	/* STMIA */
+	| ((tinstr & 0x0700) << (16 - 8))	/* Rb */
+	| (tinstr & 0x00FF);	/* mask8 */
+      break;
+default:
+	panic("undefined thumb instruction alignment fault");
+    }
+}


-------------------------------------------------------------------
Subscription options: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ:       http://www.arm.linux.org.uk/armlinux/mlfaq.php
Etiquette: http://www.arm.linux.org.uk/armlinux/mletiquette.php


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic