extable.c (1696B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 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 7 */ 8 9 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> 16 17static inline unsigned long 18get_ex_fixup(const struct exception_table_entry *ex) 19{ 20 return ((unsigned long)&ex->fixup + ex->fixup); 21} 22 23static bool ex_handler_fixup(const struct exception_table_entry *ex, 24 struct pt_regs *regs) 25{ 26 regs->epc = get_ex_fixup(ex); 27 return true; 28} 29 30static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset, 31 unsigned long val) 32{ 33 if (unlikely(offset > MAX_REG_OFFSET)) 34 return; 35 36 if (offset) 37 *(unsigned long *)((unsigned long)regs + offset) = val; 38} 39 40static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex, 41 struct pt_regs *regs) 42{ 43 int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data); 44 int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data); 45 46 regs_set_gpr(regs, reg_err * sizeof(unsigned long), -EFAULT); 47 regs_set_gpr(regs, reg_zero * sizeof(unsigned long), 0); 48 49 regs->epc = get_ex_fixup(ex); 50 return true; 51} 52 53bool fixup_exception(struct pt_regs *regs) 54{ 55 const struct exception_table_entry *ex; 56 57 ex = search_exception_tables(regs->epc); 58 if (!ex) 59 return false; 60 61 switch (ex->type) { 62 case EX_TYPE_FIXUP: 63 return ex_handler_fixup(ex, regs); 64 case EX_TYPE_BPF: 65 return ex_handler_bpf(ex, regs); 66 case EX_TYPE_UACCESS_ERR_ZERO: 67 return ex_handler_uaccess_err_zero(ex, regs); 68 } 69 70 BUG(); 71}