/* * arch/sh/mm/extable_64.c * * Copyright (C) 2003 Richard Curnow * Copyright (C) 2003, 2004 Paul Mundt * * Cloned from the 2.5 SH version.. * * 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. */ #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)©_user_memcpy) && (addr <= (unsigned long)©_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; }