1/* 2 * arch/sh/mm/extable_64.c 3 * 4 * Copyright (C) 2003 Richard Curnow 5 * Copyright (C) 2003, 2004 Paul Mundt 6 * 7 * Cloned from the 2.5 SH version.. 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file "COPYING" in the main directory of this archive 11 * for more details. 12 */ 13#include <linux/bsearch.h> 14#include <linux/rwsem.h> 15#include <linux/extable.h> 16#include <linux/uaccess.h> 17 18extern unsigned long copy_user_memcpy, copy_user_memcpy_end; 19extern void __copy_user_fixup(void); 20 21static const struct exception_table_entry __copy_user_fixup_ex = { 22 .fixup = (unsigned long)&__copy_user_fixup, 23}; 24 25/* 26 * Some functions that may trap due to a bad user-mode address have too 27 * many loads and stores in them to make it at all practical to label 28 * each one and put them all in the main exception table. 29 * 30 * In particular, the fast memcpy routine is like this. It's fix-up is 31 * just to fall back to a slow byte-at-a-time copy, which is handled the 32 * conventional way. So it's functionally OK to just handle any trap 33 * occurring in the fast memcpy with that fixup. 34 */ 35static const struct exception_table_entry *check_exception_ranges(unsigned long addr) 36{ 37 if ((addr >= (unsigned long)©_user_memcpy) && 38 (addr <= (unsigned long)©_user_memcpy_end)) 39 return &__copy_user_fixup_ex; 40 41 return NULL; 42} 43 44static int cmp_ex_search(const void *key, const void *elt) 45{ 46 const struct exception_table_entry *_elt = elt; 47 unsigned long _key = *(unsigned long *)key; 48 49 /* avoid overflow */ 50 if (_key > _elt->insn) 51 return 1; 52 if (_key < _elt->insn) 53 return -1; 54 return 0; 55} 56 57/* Simple binary search */ 58const struct exception_table_entry * 59search_extable(const struct exception_table_entry *base, 60 const size_t num, 61 unsigned long value) 62{ 63 const struct exception_table_entry *mid; 64 65 mid = check_exception_ranges(value); 66 if (mid) 67 return mid; 68 69 return bsearch(&value, base, num, 70 sizeof(struct exception_table_entry), cmp_ex_search); 71} 72 73int fixup_exception(struct pt_regs *regs) 74{ 75 const struct exception_table_entry *fixup; 76 77 fixup = search_exception_tables(regs->pc); 78 if (fixup) { 79 regs->pc = fixup->fixup; 80 return 1; 81 } 82 83 return 0; 84} 85