1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Based on arch/arm/mm/extable.c |
4 | */ |
5 | |
6 | #include <linux/bitfield.h> |
7 | #include <linux/extable.h> |
8 | #include <linux/uaccess.h> |
9 | |
10 | #include <asm/asm-extable.h> |
11 | #include <asm/ptrace.h> |
12 | |
13 | static inline unsigned long |
14 | get_ex_fixup(const struct exception_table_entry *ex) |
15 | { |
16 | return ((unsigned long)&ex->fixup + ex->fixup); |
17 | } |
18 | |
19 | static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex, |
20 | struct pt_regs *regs) |
21 | { |
22 | int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data); |
23 | int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data); |
24 | |
25 | pt_regs_write_reg(regs, reg_err, -EFAULT); |
26 | pt_regs_write_reg(regs, reg_zero, 0); |
27 | |
28 | regs->pc = get_ex_fixup(ex); |
29 | return true; |
30 | } |
31 | |
32 | static bool |
33 | ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex, |
34 | struct pt_regs *regs) |
35 | { |
36 | int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->data); |
37 | int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data); |
38 | unsigned long data, addr, offset; |
39 | |
40 | addr = pt_regs_read_reg(regs, reg_addr); |
41 | |
42 | offset = addr & 0x7UL; |
43 | addr &= ~0x7UL; |
44 | |
45 | data = *(unsigned long*)addr; |
46 | |
47 | #ifndef __AARCH64EB__ |
48 | data >>= 8 * offset; |
49 | #else |
50 | data <<= 8 * offset; |
51 | #endif |
52 | |
53 | pt_regs_write_reg(regs, reg_data, data); |
54 | |
55 | regs->pc = get_ex_fixup(ex); |
56 | return true; |
57 | } |
58 | |
59 | bool fixup_exception(struct pt_regs *regs) |
60 | { |
61 | const struct exception_table_entry *ex; |
62 | |
63 | ex = search_exception_tables(add: instruction_pointer(regs)); |
64 | if (!ex) |
65 | return false; |
66 | |
67 | switch (ex->type) { |
68 | case EX_TYPE_BPF: |
69 | return ex_handler_bpf(x: ex, regs); |
70 | case EX_TYPE_UACCESS_ERR_ZERO: |
71 | case EX_TYPE_KACCESS_ERR_ZERO: |
72 | return ex_handler_uaccess_err_zero(ex, regs); |
73 | case EX_TYPE_LOAD_UNALIGNED_ZEROPAD: |
74 | return ex_handler_load_unaligned_zeropad(ex, regs); |
75 | } |
76 | |
77 | BUG(); |
78 | } |
79 | |