Skip to content

Commit 05a68e8

Browse files
iii-ihcahca
authored andcommitted
s390/kernel: expand exception table logic to allow new handling options
This is a s390 port of commit 548acf1 ("x86/mm: Expand the exception table logic to allow new handling options"), which is needed for implementing BPF_PROBE_MEM on s390. The new handler field is made 64-bit in order to allow pointing from dynamically allocated entries to handlers in kernel text. Unlike on x86, NULL is used instead of ex_handler_default. This is because exception tables are used by boot/text_dma.S, and it would be a pain to preserve ex_handler_default. The new infrastructure is ignored in early_pgm_check_handler, since there is no pt_regs. Signed-off-by: Ilya Leoshkevich <[email protected]> Reviewed-by: Heiko Carstens <[email protected]> Signed-off-by: Heiko Carstens <[email protected]>
1 parent 88aa893 commit 05a68e8

File tree

6 files changed

+94
-17
lines changed

6 files changed

+94
-17
lines changed

arch/s390/include/asm/extable.h

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22
#ifndef __S390_EXTABLE_H
33
#define __S390_EXTABLE_H
4+
5+
#include <asm/ptrace.h>
6+
#include <linux/compiler.h>
7+
48
/*
5-
* The exception table consists of pairs of addresses: the first is the
6-
* address of an instruction that is allowed to fault, and the second is
7-
* the address at which the program should continue. No registers are
8-
* modified, so it is entirely up to the continuation code to figure out
9-
* what to do.
9+
* The exception table consists of three addresses:
10+
*
11+
* - Address of an instruction that is allowed to fault.
12+
* - Address at which the program should continue.
13+
* - Optional address of handler that takes pt_regs * argument and runs in
14+
* interrupt context.
15+
*
16+
* No registers are modified, so it is entirely up to the continuation code
17+
* to figure out what to do.
1018
*
1119
* All the routines below use bits of fixup code that are out of line
1220
* with the main instruction path. This means when everything is well,
@@ -17,6 +25,7 @@
1725
struct exception_table_entry
1826
{
1927
int insn, fixup;
28+
long handler;
2029
};
2130

2231
extern struct exception_table_entry *__start_dma_ex_table;
@@ -29,6 +38,39 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
2938
return (unsigned long)&x->fixup + x->fixup;
3039
}
3140

41+
typedef bool (*ex_handler_t)(const struct exception_table_entry *,
42+
struct pt_regs *);
43+
44+
static inline ex_handler_t
45+
ex_fixup_handler(const struct exception_table_entry *x)
46+
{
47+
if (likely(!x->handler))
48+
return NULL;
49+
return (ex_handler_t)((unsigned long)&x->handler + x->handler);
50+
}
51+
52+
static inline bool ex_handle(const struct exception_table_entry *x,
53+
struct pt_regs *regs)
54+
{
55+
ex_handler_t handler = ex_fixup_handler(x);
56+
57+
if (unlikely(handler))
58+
return handler(x, regs);
59+
regs->psw.addr = extable_fixup(x);
60+
return true;
61+
}
62+
3263
#define ARCH_HAS_RELATIVE_EXTABLE
3364

65+
static inline void swap_ex_entry_fixup(struct exception_table_entry *a,
66+
struct exception_table_entry *b,
67+
struct exception_table_entry tmp,
68+
int delta)
69+
{
70+
a->fixup = b->fixup + delta;
71+
b->fixup = tmp.fixup - delta;
72+
a->handler = b->handler + delta;
73+
b->handler = tmp.handler - delta;
74+
}
75+
3476
#endif

arch/s390/include/asm/linkage.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414

1515
#define __EX_TABLE(_section, _fault, _target) \
1616
stringify_in_c(.section _section,"a";) \
17-
stringify_in_c(.align 4;) \
17+
stringify_in_c(.align 8;) \
1818
stringify_in_c(.long (_fault) - .;) \
1919
stringify_in_c(.long (_target) - .;) \
20+
stringify_in_c(.quad 0;) \
2021
stringify_in_c(.previous)
2122

2223
#define EX_TABLE(_fault, _target) \

arch/s390/kernel/kprobes.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,10 +523,8 @@ static int kprobe_trap_handler(struct pt_regs *regs, int trapnr)
523523
* zero, try to fix up.
524524
*/
525525
entry = s390_search_extables(regs->psw.addr);
526-
if (entry) {
527-
regs->psw.addr = extable_fixup(entry);
526+
if (entry && ex_handle(entry, regs))
528527
return 1;
529-
}
530528

531529
/*
532530
* fixup_exception() could not handle it,

arch/s390/kernel/traps.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,8 @@ void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
5050
} else {
5151
const struct exception_table_entry *fixup;
5252
fixup = s390_search_extables(regs->psw.addr);
53-
if (fixup)
54-
regs->psw.addr = extable_fixup(fixup);
55-
else {
53+
if (!fixup || !ex_handle(fixup, regs))
5654
die(regs, str);
57-
}
5855
}
5956
}
6057

@@ -251,7 +248,7 @@ void monitor_event_exception(struct pt_regs *regs)
251248
case BUG_TRAP_TYPE_NONE:
252249
fixup = s390_search_extables(regs->psw.addr);
253250
if (fixup)
254-
regs->psw.addr = extable_fixup(fixup);
251+
ex_handle(fixup, regs);
255252
break;
256253
case BUG_TRAP_TYPE_WARN:
257254
break;

arch/s390/mm/fault.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,8 @@ static noinline void do_no_context(struct pt_regs *regs)
255255

256256
/* Are we prepared to handle this kernel fault? */
257257
fixup = s390_search_extables(regs->psw.addr);
258-
if (fixup) {
259-
regs->psw.addr = extable_fixup(fixup);
258+
if (fixup && ex_handle(fixup, regs))
260259
return;
261-
}
262260

263261
/*
264262
* Oops. The kernel tried to access some bad page. We'll have to

scripts/sorttable.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,45 @@ static void x86_sort_relative_table(char *extab_image, int image_size)
255255
}
256256
}
257257

258+
static void s390_sort_relative_table(char *extab_image, int image_size)
259+
{
260+
int i;
261+
262+
for (i = 0; i < image_size; i += 16) {
263+
char *loc = extab_image + i;
264+
uint64_t handler;
265+
266+
w(r((uint32_t *)loc) + i, (uint32_t *)loc);
267+
w(r((uint32_t *)(loc + 4)) + (i + 4), (uint32_t *)(loc + 4));
268+
/*
269+
* 0 is a special self-relative handler value, which means that
270+
* handler should be ignored. It is safe, because it means that
271+
* handler field points to itself, which should never happen.
272+
* When creating extable-relative values, keep it as 0, since
273+
* this should never occur either: it would mean that handler
274+
* field points to the first extable entry.
275+
*/
276+
handler = r8((uint64_t *)(loc + 8));
277+
if (handler)
278+
handler += i + 8;
279+
w8(handler, (uint64_t *)(loc + 8));
280+
}
281+
282+
qsort(extab_image, image_size / 16, 16, compare_relative_table);
283+
284+
for (i = 0; i < image_size; i += 16) {
285+
char *loc = extab_image + i;
286+
uint64_t handler;
287+
288+
w(r((uint32_t *)loc) - i, (uint32_t *)loc);
289+
w(r((uint32_t *)(loc + 4)) - (i + 4), (uint32_t *)(loc + 4));
290+
handler = r8((uint64_t *)(loc + 8));
291+
if (handler)
292+
handler -= i + 8;
293+
w8(handler, (uint64_t *)(loc + 8));
294+
}
295+
}
296+
258297
static int do_file(char const *const fname, void *addr)
259298
{
260299
int rc = -1;
@@ -297,6 +336,8 @@ static int do_file(char const *const fname, void *addr)
297336
custom_sort = x86_sort_relative_table;
298337
break;
299338
case EM_S390:
339+
custom_sort = s390_sort_relative_table;
340+
break;
300341
case EM_AARCH64:
301342
case EM_PARISC:
302343
case EM_PPC:

0 commit comments

Comments
 (0)