Linux Audio

Check our new training course

Loading...
v5.9
 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/extable.h>
11#include <linux/module.h>
12#include <linux/uaccess.h>
 
 
13
14int fixup_exception(struct pt_regs *regs)
 
15{
16	const struct exception_table_entry *fixup;
 
17
18	fixup = search_exception_tables(regs->epc);
19	if (fixup) {
20		regs->epc = fixup->fixup;
21		return 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22	}
23	return 0;
 
24}
v6.9.4
  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 unsigned long regs_get_gpr(struct pt_regs *regs, unsigned int offset)
 31{
 32	if (unlikely(!offset || offset > MAX_REG_OFFSET))
 33		return 0;
 34
 35	return *(unsigned long *)((unsigned long)regs + offset);
 36}
 37
 38static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset,
 39				unsigned long val)
 40{
 41	if (unlikely(offset > MAX_REG_OFFSET))
 42		return;
 43
 44	if (offset)
 45		*(unsigned long *)((unsigned long)regs + offset) = val;
 46}
 47
 48static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
 49					struct pt_regs *regs)
 50{
 51	int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
 52	int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
 53
 54	regs_set_gpr(regs, reg_err * sizeof(unsigned long), -EFAULT);
 55	regs_set_gpr(regs, reg_zero * sizeof(unsigned long), 0);
 56
 57	regs->epc = get_ex_fixup(ex);
 58	return true;
 59}
 60
 61static bool
 62ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
 63				  struct pt_regs *regs)
 64{
 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;
 68
 69	addr = regs_get_gpr(regs, reg_addr * sizeof(unsigned long));
 70
 71	offset = addr & 0x7UL;
 72	addr &= ~0x7UL;
 73
 74	data = *(unsigned long *)addr >> (offset * 8);
 75
 76	regs_set_gpr(regs, reg_data * sizeof(unsigned long), data);
 77
 78	regs->epc = get_ex_fixup(ex);
 79	return true;
 80}
 81
 82bool fixup_exception(struct pt_regs *regs)
 83{
 84	const struct exception_table_entry *ex;
 85
 86	ex = search_exception_tables(regs->epc);
 87	if (!ex)
 88		return false;
 89
 90	switch (ex->type) {
 91	case EX_TYPE_FIXUP:
 92		return ex_handler_fixup(ex, regs);
 93	case EX_TYPE_BPF:
 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);
 99	}
100
101	BUG();
102}