extable.c 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
  4. * Lennox Wu <[email protected]>
  5. * Chen Liqin <[email protected]>
  6. * Copyright (C) 2013 Regents of the University of California
  7. */
  8. #include <linux/bitfield.h>
  9. #include <linux/extable.h>
  10. #include <linux/module.h>
  11. #include <linux/uaccess.h>
  12. #include <asm/asm-extable.h>
  13. #include <asm/ptrace.h>
  14. static inline unsigned long
  15. get_ex_fixup(const struct exception_table_entry *ex)
  16. {
  17. return ((unsigned long)&ex->fixup + ex->fixup);
  18. }
  19. static bool ex_handler_fixup(const struct exception_table_entry *ex,
  20. struct pt_regs *regs)
  21. {
  22. regs->epc = get_ex_fixup(ex);
  23. return true;
  24. }
  25. static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset,
  26. unsigned long val)
  27. {
  28. if (unlikely(offset > MAX_REG_OFFSET))
  29. return;
  30. if (offset)
  31. *(unsigned long *)((unsigned long)regs + offset) = val;
  32. }
  33. static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
  34. struct pt_regs *regs)
  35. {
  36. int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
  37. int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
  38. regs_set_gpr(regs, reg_err * sizeof(unsigned long), -EFAULT);
  39. regs_set_gpr(regs, reg_zero * sizeof(unsigned long), 0);
  40. regs->epc = get_ex_fixup(ex);
  41. return true;
  42. }
  43. bool fixup_exception(struct pt_regs *regs)
  44. {
  45. const struct exception_table_entry *ex;
  46. ex = search_exception_tables(regs->epc);
  47. if (!ex)
  48. return false;
  49. switch (ex->type) {
  50. case EX_TYPE_FIXUP:
  51. return ex_handler_fixup(ex, regs);
  52. case EX_TYPE_BPF:
  53. return ex_handler_bpf(ex, regs);
  54. case EX_TYPE_UACCESS_ERR_ZERO:
  55. return ex_handler_uaccess_err_zero(ex, regs);
  56. }
  57. BUG();
  58. }