patch-2.3.40 linux/arch/arm/mm/fault-armv.c

Next file: linux/arch/arm/mm/fault-common.c
Previous file: linux/arch/arm/lib/uaccess.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.39/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
@@ -29,6 +29,8 @@
 #define DO_COW(m)		(!((m) & FAULT_CODE_READ))
 #define READ_FAULT(m)		((m) & FAULT_CODE_READ)
 
+extern void die_if_kernel(const char *str, struct pt_regs *regs, int err);
+
 #include "fault-common.c"
 
 #ifdef DEBUG
@@ -118,17 +120,18 @@
  * This needs to be done after sysctl_init, otherwise sys/
  * will be overwritten.
  */
-void __init alignment_init(void)
+static int __init alignment_init(void)
 {
 	create_proc_read_entry("sys/debug/alignment", 0, NULL,
-				proc_alignment_read);
+				proc_alignment_read, NULL);
+	return 0;
 }
 
 __initcall(alignment_init);
 #endif /* CONFIG_SYSCTL */
 
 static int
-do_alignment_exception(struct pt_regs *regs)
+do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
 {
 	unsigned int instr, rd, rn, correction, nr_regs, regbits;
 	unsigned long eaddr;
@@ -308,116 +311,99 @@
 	return 0;
 }
 
+#else
+
+#define do_alignment NULL
+
 #endif
 
-#define BUG_PROC_MSG \
-  "Buggy processor (%08X), trying to continue.\n" \
-  "Please read http://www.arm.linux.org.uk/state.html for more information"
+#ifdef CONFIG_DEBUG_USER
 
-asmlinkage void
-do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
+static int
+do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs)
 {
 	if (user_mode(regs)) {
-		if (addr == regs->ARM_pc) {
-			static int first = 1;
-			if (first) {
-				/*
-				 * I want statistical information on this problem!
-				 */
-				printk(KERN_ERR BUG_PROC_MSG, fsr);
-				first = 0;
+		printk("%s: permission fault on section, "
+		       "address=0x%08lx, code %d\n",
+		       current->comm, addr, error_code);
+#ifdef DEBUG
+		{
+			unsigned int i, j;
+			unsigned long *sp;
+
+			sp = (unsigned long *) (regs->ARM_sp - 128);
+			for (j = 0; j < 20 && sp_valid(sp); j++) {
+				printk("%p: ", sp);
+				for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++)
+					printk("%08lx ", *sp);
+				printk("\n");
 			}
-			return;
+			show_regs(regs);
+			c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
 		}
+#endif
 	}
+	return 1;	/* not fixed up */
+}
+#else
 
-#define DIE(signr,nam)\
-		force_sig(signr, current);\
-		die(nam, regs, fsr);\
-		do_exit(signr);\
-		break
-
-	switch (fsr & 15) {
-	/*
-	 *  0 - vector exception
-	 */
-	case 0:
-		force_sig(SIGSEGV, current);
-		if (!user_mode(regs)) {
-			die("vector exception", regs, fsr);
-			do_exit(SIGSEGV);
-		}
-		break;
+#define do_sect_fault NULL
 
-	/*
-	 * 15 - permission fault on page
-	 *  5 - page-table entry descriptor fault
-	 *  7 - first-level descriptor fault
-	 */
-	case 15: case 5: case 7:
-		do_page_fault(addr, error_code, regs);
-		break;
-
-	/*
-	 * 13 - permission fault on section
-	 */
-	case 13:
-		force_sig(SIGSEGV, current);
-		if (!user_mode(regs)) {
-			die("section permission fault", regs, fsr);
-			do_exit(SIGSEGV);
-		} else {
-#ifdef CONFIG_DEBUG_USER
-			printk("%s: permission fault on section, "
-			       "address=0x%08lx, code %d\n",
-			       current->comm, addr, error_code);
-#ifdef DEBUG
-			{
-				unsigned int i, j;
-				unsigned long *sp;
-
-				sp = (unsigned long *) (regs->ARM_sp - 128);
-				for (j = 0; j < 20 && sp_valid(sp); j++) {
-					printk("%p: ", sp);
-					for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++)
-						printk("%08lx ", *sp);
-					printk("\n");
-				}
-				show_regs(regs);
-				c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
-			}
-#endif
 #endif
+
+static struct fsr_info {
+	int	(*fn)(unsigned long addr, int error_code, struct pt_regs *regs);
+	int	sig;
+	char	*name;
+} fsr_info[] = {
+	{ NULL,			SIGSEGV, "vector exception"		   },
+	{ do_alignment,		SIGBUS,	 "alignment exception"		   },
+	{ NULL,			SIGKILL, "terminal exception"		   },
+	{ do_alignment,		SIGBUS,	 "alignment exception"		   },
+	{ NULL,			SIGBUS,	 "external abort on linefetch"	   },
+	{ do_page_fault,	SIGSEGV, "page fault"			   },
+	{ NULL,			SIGBUS,	 "external abort on linefetch"	   },
+	{ do_page_fault,	SIGSEGV, "page fault"			   },
+	{ NULL,			SIGBUS,	 "external abort on non-linefetch" },
+	{ NULL,			SIGSEGV, "domain fault"			   },
+	{ NULL,			SIGBUS,	 "external abort on non-linefetch" },
+	{ NULL,			SIGSEGV, "domain fault"			   },
+	{ NULL,			SIGBUS,	 "external abort on translation"   },
+	{ do_sect_fault,	SIGSEGV, "section permission fault"	   },
+	{ NULL,			SIGBUS,	 "external abort on translation"   },
+	{ do_page_fault,	SIGSEGV, "page permission fault"	   }
+};
+
+/*
+ * Currently dropped down to debug level
+ */
+#define BUG_PROC_MSG \
+  KERN_DEBUG "Weird data abort (%08X).\n" \
+  KERN_DEBUG "Please see http://www.arm.linux.org.uk/state.html for more information"
+
+asmlinkage void
+do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
+{
+	struct fsr_info *inf;
+
+	if (user_mode(regs) && addr == regs->ARM_pc) {
+		static int first = 1;
+		if (first) {
+			/*
+			 * I want statistical information on this problem,
+			 * but we don't want to hastle the users too much.
+			 */
+			printk(BUG_PROC_MSG, fsr);
+			first = 0;
 		}
-		break;
+		return;
+	}
 
-	case 1:
-	case 3:
-#ifdef CONFIG_ALIGNMENT_TRAP
-		if (!do_alignment_exception(regs))
-			break;
-#endif
-		/*
-		 * this should never happen
-		 */
-		DIE(SIGBUS, "Alignment exception");
-		break;
+	inf = fsr_info + (fsr & 15);
 
-	case 2:
-		DIE(SIGKILL, "Terminal exception");
-	case 12:
-	case 14:
-		DIE(SIGBUS, "External abort on translation");
-	case 9:
-	case 11:
-		DIE(SIGSEGV, "Domain fault");
-
-	case 4:
-	case 6:
-		DIE(SIGBUS, "External abort on linefetch");
-	case 8:
-	case 10:
-		DIE(SIGBUS, "External abort on non-linefetch");
+	if (!inf->fn || inf->fn(addr, error_code, regs)) {
+		force_sig(inf->sig, current);
+		die_if_kernel(inf->name, regs, fsr);
 	}
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)