1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef __S390_EXTABLE_H
3*4882a593Smuzhiyun #define __S390_EXTABLE_H
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include <asm/ptrace.h>
6*4882a593Smuzhiyun #include <linux/compiler.h>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun /*
9*4882a593Smuzhiyun * The exception table consists of three addresses:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * - Address of an instruction that is allowed to fault.
12*4882a593Smuzhiyun * - Address at which the program should continue.
13*4882a593Smuzhiyun * - Optional address of handler that takes pt_regs * argument and runs in
14*4882a593Smuzhiyun * interrupt context.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * No registers are modified, so it is entirely up to the continuation code
17*4882a593Smuzhiyun * to figure out what to do.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * All the routines below use bits of fixup code that are out of line
20*4882a593Smuzhiyun * with the main instruction path. This means when everything is well,
21*4882a593Smuzhiyun * we don't even have to jump over them. Further, they do not intrude
22*4882a593Smuzhiyun * on our cache or tlb entries.
23*4882a593Smuzhiyun */
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun struct exception_table_entry
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun int insn, fixup;
28*4882a593Smuzhiyun long handler;
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun extern struct exception_table_entry *__start_dma_ex_table;
32*4882a593Smuzhiyun extern struct exception_table_entry *__stop_dma_ex_table;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun const struct exception_table_entry *s390_search_extables(unsigned long addr);
35*4882a593Smuzhiyun
extable_fixup(const struct exception_table_entry * x)36*4882a593Smuzhiyun static inline unsigned long extable_fixup(const struct exception_table_entry *x)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun return (unsigned long)&x->fixup + x->fixup;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun typedef bool (*ex_handler_t)(const struct exception_table_entry *,
42*4882a593Smuzhiyun struct pt_regs *);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static inline ex_handler_t
ex_fixup_handler(const struct exception_table_entry * x)45*4882a593Smuzhiyun ex_fixup_handler(const struct exception_table_entry *x)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun if (likely(!x->handler))
48*4882a593Smuzhiyun return NULL;
49*4882a593Smuzhiyun return (ex_handler_t)((unsigned long)&x->handler + x->handler);
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
ex_handle(const struct exception_table_entry * x,struct pt_regs * regs)52*4882a593Smuzhiyun static inline bool ex_handle(const struct exception_table_entry *x,
53*4882a593Smuzhiyun struct pt_regs *regs)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun ex_handler_t handler = ex_fixup_handler(x);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun if (unlikely(handler))
58*4882a593Smuzhiyun return handler(x, regs);
59*4882a593Smuzhiyun regs->psw.addr = extable_fixup(x);
60*4882a593Smuzhiyun return true;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #define ARCH_HAS_RELATIVE_EXTABLE
64*4882a593Smuzhiyun
swap_ex_entry_fixup(struct exception_table_entry * a,struct exception_table_entry * b,struct exception_table_entry tmp,int delta)65*4882a593Smuzhiyun static inline void swap_ex_entry_fixup(struct exception_table_entry *a,
66*4882a593Smuzhiyun struct exception_table_entry *b,
67*4882a593Smuzhiyun struct exception_table_entry tmp,
68*4882a593Smuzhiyun int delta)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun a->fixup = b->fixup + delta;
71*4882a593Smuzhiyun b->fixup = tmp.fixup - delta;
72*4882a593Smuzhiyun a->handler = b->handler;
73*4882a593Smuzhiyun if (a->handler)
74*4882a593Smuzhiyun a->handler += delta;
75*4882a593Smuzhiyun b->handler = tmp.handler;
76*4882a593Smuzhiyun if (b->handler)
77*4882a593Smuzhiyun b->handler -= delta;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun #define swap_ex_entry_fixup swap_ex_entry_fixup
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun #endif
82