1/* 2 * linux/arch/frv/mm/extable.c 3 */ 4 5#include <linux/module.h> 6#include <linux/spinlock.h> 7#include <asm/uaccess.h> 8 9extern const struct exception_table_entry __attribute__((aligned(8))) __start___ex_table[]; 10extern const struct exception_table_entry __attribute__((aligned(8))) __stop___ex_table[]; 11extern const void __memset_end, __memset_user_error_lr, __memset_user_error_handler; 12extern const void __memcpy_end, __memcpy_user_error_lr, __memcpy_user_error_handler; 13extern spinlock_t modlist_lock; 14 15/*****************************************************************************/ 16/* 17 * 18 */ 19static inline unsigned long search_one_table(const struct exception_table_entry *first, 20 const struct exception_table_entry *last, 21 unsigned long value) 22{ 23 while (first <= last) { 24 const struct exception_table_entry __attribute__((aligned(8))) *mid; 25 long diff; 26 27 mid = (last - first) / 2 + first; 28 diff = mid->insn - value; 29 if (diff == 0) 30 return mid->fixup; 31 else if (diff < 0) 32 first = mid + 1; 33 else 34 last = mid - 1; 35 } 36 return 0; 37} /* end search_one_table() */ 38 39/*****************************************************************************/ 40/* 41 * see if there's a fixup handler available to deal with a kernel fault 42 */ 43unsigned long search_exception_table(unsigned long pc) 44{ 45 const struct exception_table_entry *extab; 46 47 /* determine if the fault lay during a memcpy_user or a memset_user */ 48 if (__frame->lr == (unsigned long) &__memset_user_error_lr && 49 (unsigned long) &memset <= pc && pc < (unsigned long) &__memset_end 50 ) { 51 /* the fault occurred in a protected memset 52 * - we search for the return address (in LR) instead of the program counter 53 * - it was probably during a clear_user() 54 */ 55 return (unsigned long) &__memset_user_error_handler; 56 } 57 58 if (__frame->lr == (unsigned long) &__memcpy_user_error_lr && 59 (unsigned long) &memcpy <= pc && pc < (unsigned long) &__memcpy_end 60 ) { 61 /* the fault occurred in a protected memset 62 * - we search for the return address (in LR) instead of the program counter 63 * - it was probably during a copy_to/from_user() 64 */ 65 return (unsigned long) &__memcpy_user_error_handler; 66 } 67 68 extab = search_exception_tables(pc); 69 if (extab) 70 return extab->fixup; 71 72 return 0; 73 74} /* end search_exception_table() */ 75