Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/riscv/mm/extable.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
4
* Lennox Wu <[email protected]>
5
* Chen Liqin <[email protected]>
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
17
static inline unsigned long
18
get_ex_fixup(const struct exception_table_entry *ex)
19
{
20
return ((unsigned long)&ex->fixup + ex->fixup);
21
}
22
23
static 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
30
static 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
38
static 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
48
static 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
61
static bool
62
ex_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
82
bool 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
}
103
104