1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
4 * Lennox Wu <lennox.wu@sunplusct.com>
5 * Chen Liqin <liqin.chen@sunplusct.com>
6 * Copyright (C) 2013 Regents of the University of California
10 #include <linux/bitfield.h>
11 #include <linux/extable.h>
12 #include <linux/module.h>
13 #include <linux/uaccess.h>
14 #include <asm/asm-extable.h>
15 #include <asm/ptrace.h>
17 static inline unsigned long
18 get_ex_fixup(const struct exception_table_entry
*ex
)
20 return ((unsigned long)&ex
->fixup
+ ex
->fixup
);
23 static bool ex_handler_fixup(const struct exception_table_entry
*ex
,
26 regs
->epc
= get_ex_fixup(ex
);
30 static inline unsigned long regs_get_gpr(struct pt_regs
*regs
, unsigned int offset
)
32 if (unlikely(!offset
|| offset
> MAX_REG_OFFSET
))
35 return *(unsigned long *)((unsigned long)regs
+ offset
);
38 static inline void regs_set_gpr(struct pt_regs
*regs
, unsigned int offset
,
41 if (unlikely(offset
> MAX_REG_OFFSET
))
45 *(unsigned long *)((unsigned long)regs
+ offset
) = val
;
48 static bool ex_handler_uaccess_err_zero(const struct exception_table_entry
*ex
,
51 int reg_err
= FIELD_GET(EX_DATA_REG_ERR
, ex
->data
);
52 int reg_zero
= FIELD_GET(EX_DATA_REG_ZERO
, ex
->data
);
54 regs_set_gpr(regs
, reg_err
* sizeof(unsigned long), -EFAULT
);
55 regs_set_gpr(regs
, reg_zero
* sizeof(unsigned long), 0);
57 regs
->epc
= get_ex_fixup(ex
);
62 ex_handler_load_unaligned_zeropad(const struct exception_table_entry
*ex
,
65 int reg_data
= FIELD_GET(EX_DATA_REG_DATA
, ex
->data
);
66 int reg_addr
= FIELD_GET(EX_DATA_REG_ADDR
, ex
->data
);
67 unsigned long data
, addr
, offset
;
69 addr
= regs_get_gpr(regs
, reg_addr
* sizeof(unsigned long));
71 offset
= addr
& 0x7UL
;
74 data
= *(unsigned long *)addr
>> (offset
* 8);
76 regs_set_gpr(regs
, reg_data
* sizeof(unsigned long), data
);
78 regs
->epc
= get_ex_fixup(ex
);
82 bool fixup_exception(struct pt_regs
*regs
)
84 const struct exception_table_entry
*ex
;
86 ex
= search_exception_tables(regs
->epc
);
92 return ex_handler_fixup(ex
, regs
);
94 return ex_handler_bpf(ex
, regs
);
95 case EX_TYPE_UACCESS_ERR_ZERO
:
96 return ex_handler_uaccess_err_zero(ex
, regs
);
97 case EX_TYPE_LOAD_UNALIGNED_ZEROPAD
:
98 return ex_handler_load_unaligned_zeropad(ex
, regs
);