linux/arch/frv/mm/extable.c
<<
>>
Prefs
   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