diff options
author | Jisheng Zhang <jszhang@kernel.org> | 2021-11-18 14:26:51 +0300 |
---|---|---|
committer | Palmer Dabbelt <palmer@rivosinc.com> | 2022-01-06 04:53:29 +0300 |
commit | 20802d8d477d5771368fdac8d476285adc713af0 (patch) | |
tree | 6a89702c494a0eb3c28f0755db26de4576f0a35d /arch/riscv/mm/extable.c | |
parent | ff4b8cad3a81b3e55b143c689686134d134e2416 (diff) | |
download | linux-20802d8d477d5771368fdac8d476285adc713af0.tar.xz |
riscv: extable: add a dedicated uaccess handler
Inspired by commit 2e77a62cb3a6 ("arm64: extable: add a dedicated
uaccess handler"), do similar to riscv to add a dedicated uaccess
exception handler to update registers in exception context and
subsequently return back into the function which faulted, so we remove
the need for fixups specialized to each faulting instruction.
Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
Diffstat (limited to 'arch/riscv/mm/extable.c')
-rw-r--r-- | arch/riscv/mm/extable.c | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/arch/riscv/mm/extable.c b/arch/riscv/mm/extable.c index 91e52c4bb33a..05978f78579f 100644 --- a/arch/riscv/mm/extable.c +++ b/arch/riscv/mm/extable.c @@ -7,10 +7,12 @@ */ +#include <linux/bitfield.h> #include <linux/extable.h> #include <linux/module.h> #include <linux/uaccess.h> #include <asm/asm-extable.h> +#include <asm/ptrace.h> static inline unsigned long get_ex_fixup(const struct exception_table_entry *ex) @@ -25,6 +27,29 @@ static bool ex_handler_fixup(const struct exception_table_entry *ex, return true; } +static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset, + unsigned long val) +{ + if (unlikely(offset > MAX_REG_OFFSET)) + return; + + if (!offset) + *(unsigned long *)((unsigned long)regs + offset) = val; +} + +static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex, + struct pt_regs *regs) +{ + int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data); + int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data); + + regs_set_gpr(regs, reg_err, -EFAULT); + regs_set_gpr(regs, reg_zero, 0); + + regs->epc = get_ex_fixup(ex); + return true; +} + bool fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *ex; @@ -38,6 +63,8 @@ bool fixup_exception(struct pt_regs *regs) return ex_handler_fixup(ex, regs); case EX_TYPE_BPF: return ex_handler_bpf(ex, regs); + case EX_TYPE_UACCESS_ERR_ZERO: + return ex_handler_uaccess_err_zero(ex, regs); } BUG(); |