extable_64.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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/rwsem.h>
  14. #include <linux/module.h>
  15. #include <asm/uaccess.h>
  16. extern unsigned long copy_user_memcpy, copy_user_memcpy_end;
  17. extern void __copy_user_fixup(void);
  18. static const struct exception_table_entry __copy_user_fixup_ex = {
  19. .fixup = (unsigned long)&__copy_user_fixup,
  20. };
  21. /*
  22. * Some functions that may trap due to a bad user-mode address have too
  23. * many loads and stores in them to make it at all practical to label
  24. * each one and put them all in the main exception table.
  25. *
  26. * In particular, the fast memcpy routine is like this. It's fix-up is
  27. * just to fall back to a slow byte-at-a-time copy, which is handled the
  28. * conventional way. So it's functionally OK to just handle any trap
  29. * occurring in the fast memcpy with that fixup.
  30. */
  31. static const struct exception_table_entry *check_exception_ranges(unsigned long addr)
  32. {
  33. if ((addr >= (unsigned long)&copy_user_memcpy) &&
  34. (addr <= (unsigned long)&copy_user_memcpy_end))
  35. return &__copy_user_fixup_ex;
  36. return NULL;
  37. }
  38. /* Simple binary search */
  39. const struct exception_table_entry *
  40. search_extable(const struct exception_table_entry *first,
  41. const struct exception_table_entry *last,
  42. unsigned long value)
  43. {
  44. const struct exception_table_entry *mid;
  45. mid = check_exception_ranges(value);
  46. if (mid)
  47. return mid;
  48. while (first <= last) {
  49. long diff;
  50. mid = (last - first) / 2 + first;
  51. diff = mid->insn - value;
  52. if (diff == 0)
  53. return mid;
  54. else if (diff < 0)
  55. first = mid+1;
  56. else
  57. last = mid-1;
  58. }
  59. return NULL;
  60. }
  61. int fixup_exception(struct pt_regs *regs)
  62. {
  63. const struct exception_table_entry *fixup;
  64. fixup = search_exception_tables(regs->pc);
  65. if (fixup) {
  66. regs->pc = fixup->fixup;
  67. return 1;
  68. }
  69. return 0;
  70. }