extable.c 2.4 KB

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