From 83ce3ac1d13f9a3ae83485a5e5a1cb85faf865ff Mon Sep 17 00:00:00 2001
From: Paul Mundt <lethal@linux-sh.org>
Date: Sun, 11 Nov 2007 17:24:50 +0900
Subject: sh: Split out extable.c _32 and _64 variants.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/mm/extable_64.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)
 create mode 100644 arch/sh/mm/extable_64.c

(limited to 'arch/sh/mm/extable_64.c')

diff --git a/arch/sh/mm/extable_64.c b/arch/sh/mm/extable_64.c
new file mode 100644
index 00000000000..a2e6e056377
--- /dev/null
+++ b/arch/sh/mm/extable_64.c
@@ -0,0 +1,80 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * arch/sh64/mm/extable.c
+ *
+ * Copyright (C) 2003 Richard Curnow
+ * Copyright (C) 2003, 2004  Paul Mundt
+ *
+ * Cloned from the 2.5 SH version..
+ */
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern unsigned long copy_user_memcpy, copy_user_memcpy_end;
+extern void __copy_user_fixup(void);
+
+static const struct exception_table_entry __copy_user_fixup_ex = {
+	.fixup = (unsigned long)&__copy_user_fixup,
+};
+
+/* Some functions that may trap due to a bad user-mode address have too many loads
+   and stores in them to make it at all practical to label each one and put them all in
+   the main exception table.
+
+   In particular, the fast memcpy routine is like this.  It's fix-up is just to fall back
+   to a slow byte-at-a-time copy, which is handled the conventional way.  So it's functionally
+   OK to just handle any trap occurring in the fast memcpy with that fixup. */
+static const struct exception_table_entry *check_exception_ranges(unsigned long addr)
+{
+	if ((addr >= (unsigned long)&copy_user_memcpy) &&
+	    (addr <= (unsigned long)&copy_user_memcpy_end))
+		return &__copy_user_fixup_ex;
+
+	return NULL;
+}
+
+/* Simple binary search */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+		 const struct exception_table_entry *last,
+		 unsigned long value)
+{
+	const struct exception_table_entry *mid;
+
+	mid = check_exception_ranges(value);
+	if (mid)
+		return mid;
+
+        while (first <= last) {
+		long diff;
+
+		mid = (last - first) / 2 + first;
+		diff = mid->insn - value;
+                if (diff == 0)
+                        return mid;
+                else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+
+        return NULL;
+}
+
+int fixup_exception(struct pt_regs *regs)
+{
+	const struct exception_table_entry *fixup;
+
+	fixup = search_exception_tables(regs->pc);
+	if (fixup) {
+		regs->pc = fixup->fixup;
+		return 1;
+	}
+
+	return 0;
+}
+
-- 
cgit v1.2.3-18-g5258