extable.c 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  4. */
  5. #include <linux/bitfield.h>
  6. #include <linux/extable.h>
  7. #include <linux/uaccess.h>
  8. #include <asm/asm-extable.h>
  9. #include <asm/branch.h>
  10. static inline unsigned long
  11. get_ex_fixup(const struct exception_table_entry *ex)
  12. {
  13. return ((unsigned long)&ex->fixup + ex->fixup);
  14. }
  15. static inline void regs_set_gpr(struct pt_regs *regs,
  16. unsigned int offset, unsigned long val)
  17. {
  18. if (offset && offset <= MAX_REG_OFFSET)
  19. *(unsigned long *)((unsigned long)regs + offset) = val;
  20. }
  21. static bool ex_handler_fixup(const struct exception_table_entry *ex,
  22. struct pt_regs *regs)
  23. {
  24. regs->csr_era = get_ex_fixup(ex);
  25. return true;
  26. }
  27. static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
  28. struct pt_regs *regs)
  29. {
  30. int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
  31. int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
  32. regs_set_gpr(regs, reg_err * sizeof(unsigned long), -EFAULT);
  33. regs_set_gpr(regs, reg_zero * sizeof(unsigned long), 0);
  34. regs->csr_era = get_ex_fixup(ex);
  35. return true;
  36. }
  37. bool fixup_exception(struct pt_regs *regs)
  38. {
  39. const struct exception_table_entry *ex;
  40. ex = search_exception_tables(exception_era(regs));
  41. if (!ex)
  42. return false;
  43. switch (ex->type) {
  44. case EX_TYPE_FIXUP:
  45. return ex_handler_fixup(ex, regs);
  46. case EX_TYPE_UACCESS_ERR_ZERO:
  47. return ex_handler_uaccess_err_zero(ex, regs);
  48. case EX_TYPE_BPF:
  49. return ex_handler_bpf(ex, regs);
  50. }
  51. BUG();
  52. }