blob: 4894553096951f326944207737d28fdddb4b1e4c [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Catalin Marinas1d18c472012-03-05 11:49:27 +00002/*
3 * Based on arch/arm/mm/extable.c
4 */
5
Mark Rutland2e77a622021-10-19 17:02:17 +01006#include <linux/bitfield.h>
Paul Gortmaker0edfa832016-09-19 17:38:55 -04007#include <linux/extable.h>
Catalin Marinas1d18c472012-03-05 11:49:27 +00008#include <linux/uaccess.h>
9
Mark Rutlandd6e2cc52021-10-19 17:02:16 +010010#include <asm/asm-extable.h>
Mark Rutland2e77a622021-10-19 17:02:17 +010011#include <asm/ptrace.h>
Mark Rutlandd6e2cc52021-10-19 17:02:16 +010012
Mark Rutlandd6e2cc52021-10-19 17:02:16 +010013static inline unsigned long
14get_ex_fixup(const struct exception_table_entry *ex)
15{
16 return ((unsigned long)&ex->fixup + ex->fixup);
17}
18
19static bool ex_handler_fixup(const struct exception_table_entry *ex,
20 struct pt_regs *regs)
21{
22 regs->pc = get_ex_fixup(ex);
23 return true;
24}
25
Mark Rutland2e77a622021-10-19 17:02:17 +010026static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
27 struct pt_regs *regs)
28{
29 int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
30 int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
31
32 pt_regs_write_reg(regs, reg_err, -EFAULT);
33 pt_regs_write_reg(regs, reg_zero, 0);
34
35 regs->pc = get_ex_fixup(ex);
36 return true;
37}
38
Mark Rutland753b3232021-10-19 17:02:18 +010039static bool
40ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
41 struct pt_regs *regs)
42{
Evgenii Stepanov3758a6c2022-01-25 10:22:17 -080043 int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->data);
44 int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
Mark Rutland753b3232021-10-19 17:02:18 +010045 unsigned long data, addr, offset;
46
47 addr = pt_regs_read_reg(regs, reg_addr);
48
49 offset = addr & 0x7UL;
50 addr &= ~0x7UL;
51
52 data = *(unsigned long*)addr;
53
54#ifndef __AARCH64EB__
55 data >>= 8 * offset;
56#else
57 data <<= 8 * offset;
58#endif
59
60 pt_regs_write_reg(regs, reg_data, data);
61
62 regs->pc = get_ex_fixup(ex);
63 return true;
64}
65
Mark Rutlande8c328d2021-10-19 17:02:14 +010066bool fixup_exception(struct pt_regs *regs)
Catalin Marinas1d18c472012-03-05 11:49:27 +000067{
Mark Rutland5d0e7902021-10-19 17:02:15 +010068 const struct exception_table_entry *ex;
Catalin Marinas1d18c472012-03-05 11:49:27 +000069
Mark Rutland5d0e7902021-10-19 17:02:15 +010070 ex = search_exception_tables(instruction_pointer(regs));
71 if (!ex)
Mark Rutlande8c328d2021-10-19 17:02:14 +010072 return false;
Catalin Marinas1d18c472012-03-05 11:49:27 +000073
Mark Rutlandd6e2cc52021-10-19 17:02:16 +010074 switch (ex->type) {
75 case EX_TYPE_FIXUP:
76 return ex_handler_fixup(ex, regs);
77 case EX_TYPE_BPF:
78 return ex_handler_bpf(ex, regs);
Mark Rutland2e77a622021-10-19 17:02:17 +010079 case EX_TYPE_UACCESS_ERR_ZERO:
80 return ex_handler_uaccess_err_zero(ex, regs);
Mark Rutland753b3232021-10-19 17:02:18 +010081 case EX_TYPE_LOAD_UNALIGNED_ZEROPAD:
82 return ex_handler_load_unaligned_zeropad(ex, regs);
Mark Rutlandd6e2cc52021-10-19 17:02:16 +010083 }
Jean-Philippe Brucker80083422020-07-28 17:21:26 +020084
Mark Rutlandd6e2cc52021-10-19 17:02:16 +010085 BUG();
Catalin Marinas1d18c472012-03-05 11:49:27 +000086}