Skip to content

Commit 0875816

Browse files
committed
Merge branch 'warn-exception'
Heiko Carstens says: ==================== v2: - Use generic WARN() implementation in case of gcc-8, which avoids the need to raise the minimum gcc version to gcc-9 for (only) s390 - Add couple of additional ifdef guards to avoid compile errors and warnings v1 ([1]): Use the generic infrastructure introduced by Peter Zijlstra [2] to implement an exception based WARN() and WARN_ONCE() similar to x86. Due to some compiler oddities on s390 this requires to raise the minimum gcc version to 9. Maybe there are ways to avoid this, but I failed to find a working solution. Details are in the patch descriptions. Just posting this now to also get some compile bot testing, since I'm afraid there might be some compiler version / config option around where even this new approach breaks. Peter, since you were wondering: your generic infrastructure pieces work very nice. Looking at the x86 and s390 implementation: it might be possible to make things even more generic since both __WARN_printf(), and WARN_ONCE() are identical; it looks like only __WARN_print_arg() needs to be provided. [1] https://lore.kernel.org/all/20251209121701.1856271-1-hca@linux.ibm.com/ [2] https://lore.kernel.org/all/20251110114633.202485143@infradead.org/ ==================== Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
2 parents 88303fb + 9f9d68c commit 0875816

6 files changed

Lines changed: 169 additions & 41 deletions

File tree

arch/s390/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ config CC_HAS_ASM_AOR_FORMAT_FLAGS
6969
Clang versions before 19.1.0 do not support A,
7070
O, and R inline assembly format flags.
7171

72+
config CC_HAS_ASM_IMMEDIATE_STRINGS
73+
def_bool !(CC_IS_GCC && GCC_VERSION < 90000)
74+
help
75+
GCC versions before 9.0.0 cannot handle strings as immediate
76+
input operands in inline assemblies.
77+
7278
config CC_HAS_STACKPROTECTOR_GLOBAL
7379
def_bool $(cc-option, -mstack-protector-guard=global -mstack-protector-guard-record)
7480

arch/s390/include/asm/asm-prototypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <linux/kvm_host.h>
55
#include <linux/ftrace.h>
6+
#include <asm/bug.h>
67
#include <asm/fpu.h>
78
#include <asm/nospec-branch.h>
89
#include <asm-generic/asm-prototypes.h>

arch/s390/include/asm/bug.h

Lines changed: 104 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,127 @@
22
#ifndef _ASM_S390_BUG_H
33
#define _ASM_S390_BUG_H
44

5-
#include <linux/stringify.h>
5+
#include <linux/compiler.h>
6+
#include <linux/const.h>
67

7-
#ifdef CONFIG_BUG
8+
#define MONCODE_BUG _AC(0, U)
9+
#define MONCODE_BUG_ARG _AC(1, U)
810

9-
#ifndef CONFIG_DEBUG_BUGVERBOSE
10-
#define _BUGVERBOSE_LOCATION(file, line)
11+
#ifndef __ASSEMBLER__
12+
#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS)
13+
14+
#ifdef CONFIG_DEBUG_BUGVERBOSE
15+
#define __BUG_ENTRY_VERBOSE(format, file, line) \
16+
" .long " format " - . # bug_entry::format\n" \
17+
" .long " file " - . # bug_entry::file\n" \
18+
" .short " line " # bug_entry::line\n"
1119
#else
12-
#define __BUGVERBOSE_LOCATION(file, line) \
13-
.pushsection .rodata.str, "aMS", @progbits, 1; \
14-
.align 2; \
15-
10002: .ascii file "\0"; \
16-
.popsection; \
17-
\
18-
.long 10002b - .; \
19-
.short line;
20-
#define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line)
20+
#define __BUG_ENTRY_VERBOSE(format, file, line)
2121
#endif
2222

23-
#ifndef CONFIG_GENERIC_BUG
24-
#define __BUG_ENTRY(cond_str, flags)
23+
#ifdef CONFIG_DEBUG_BUGVERBOSE_DETAILED
24+
#define WARN_CONDITION_STR(cond_str) cond_str
2525
#else
26-
#define __BUG_ENTRY(cond_str, flags) \
27-
.pushsection __bug_table, "aw"; \
28-
.align 4; \
29-
10000: .long 10001f - .; \
30-
_BUGVERBOSE_LOCATION(WARN_CONDITION_STR(cond_str) __FILE__, __LINE__) \
31-
.short flags; \
32-
.popsection; \
33-
10001:
26+
#define WARN_CONDITION_STR(cond_str) ""
3427
#endif
3528

36-
#define ASM_BUG_FLAGS(cond_str, flags) \
37-
__BUG_ENTRY(cond_str, flags) \
38-
mc 0,0
29+
#define __BUG_ENTRY(format, file, line, flags, size) \
30+
" .section __bug_table,\"aw\"\n" \
31+
"1: .long 0b - . # bug_entry::bug_addr\n" \
32+
__BUG_ENTRY_VERBOSE(format, file, line) \
33+
" .short "flags" # bug_entry::flags\n" \
34+
" .org 1b+"size"\n" \
35+
" .previous"
3936

40-
#define ASM_BUG() ASM_BUG_FLAGS("", 0)
37+
#define __BUG_ASM(cond_str, flags) \
38+
do { \
39+
asm_inline volatile("\n" \
40+
"0: mc %[monc](%%r0),0\n" \
41+
__BUG_ENTRY("%[frmt]", "%[file]", "%[line]", \
42+
"%[flgs]", "%[size]") \
43+
: \
44+
: [monc] "i" (MONCODE_BUG), \
45+
[frmt] "i" (WARN_CONDITION_STR(cond_str)), \
46+
[file] "i" (__FILE__), \
47+
[line] "i" (__LINE__), \
48+
[flgs] "i" (flags), \
49+
[size] "i" (sizeof(struct bug_entry))); \
50+
} while (0)
4151

42-
#define __BUG_FLAGS(cond_str, flags) \
43-
asm_inline volatile(__stringify(ASM_BUG_FLAGS(cond_str, flags)));
52+
#define BUG() \
53+
do { \
54+
__BUG_ASM("", 0); \
55+
unreachable(); \
56+
} while (0)
4457

45-
#define __WARN_FLAGS(cond_str, flags) \
46-
do { \
47-
__BUG_FLAGS(cond_str, BUGFLAG_WARNING|(flags)); \
58+
#define __WARN_FLAGS(cond_str, flags) \
59+
do { \
60+
__BUG_ASM(cond_str, BUGFLAG_WARNING | (flags)); \
4861
} while (0)
4962

50-
#define BUG() \
51-
do { \
52-
__BUG_FLAGS("", 0); \
53-
unreachable(); \
63+
#define __WARN_bug_entry(flags, format) \
64+
({ \
65+
struct bug_entry *bug; \
66+
\
67+
asm_inline volatile("\n" \
68+
"0: larl %[bug],1f\n" \
69+
__BUG_ENTRY("%[frmt]", "%[file]", "%[line]", \
70+
"%[flgs]", "%[size]") \
71+
: [bug] "=d" (bug) \
72+
: [frmt] "i" (format), \
73+
[file] "i" (__FILE__), \
74+
[line] "i" (__LINE__), \
75+
[flgs] "i" (flags), \
76+
[size] "i" (sizeof(struct bug_entry))); \
77+
bug; \
78+
})
79+
80+
/*
81+
* Variable Argument List (va_list) as defined in ELF Application
82+
* Binary Interface s390x Supplement documentation.
83+
*/
84+
struct arch_va_list {
85+
long __gpr;
86+
long __fpr;
87+
void *__overflow_arg_area;
88+
void *__reg_save_area;
89+
};
90+
91+
struct bug_entry;
92+
struct pt_regs;
93+
94+
void *__warn_args(struct arch_va_list *args, struct pt_regs *regs);
95+
void __WARN_trap(struct bug_entry *bug, ...);
96+
97+
#define __WARN_print_arg(flags, format, arg...) \
98+
do { \
99+
int __flags = (flags) | BUGFLAG_WARNING | BUGFLAG_ARGS; \
100+
\
101+
__WARN_trap(__WARN_bug_entry(__flags, format), ## arg); \
102+
/* prevent tail-call optimization */ \
103+
asm(""); \
54104
} while (0)
55105

106+
#define __WARN_printf(taint, fmt, arg...) \
107+
__WARN_print_arg(BUGFLAG_TAINT(taint), fmt, ## arg)
108+
109+
#define WARN_ONCE(cond, format, arg...) \
110+
({ \
111+
int __ret_warn_on = !!(cond); \
112+
\
113+
if (unlikely(__ret_warn_on)) { \
114+
__WARN_print_arg(BUGFLAG_ONCE|BUGFLAG_TAINT(TAINT_WARN),\
115+
format, ## arg); \
116+
} \
117+
__ret_warn_on; \
118+
})
119+
56120
#define HAVE_ARCH_BUG
121+
#define HAVE_ARCH_BUG_FORMAT
122+
#define HAVE_ARCH_BUG_FORMAT_ARGS
57123

58-
#endif /* CONFIG_BUG */
124+
#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */
125+
#endif /* __ASSEMBLER__ */
59126

60127
#include <asm-generic/bug.h>
61128

arch/s390/include/asm/ptrace.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,10 @@ struct pt_regs {
120120
unsigned long gprs[NUM_GPRS];
121121
};
122122
};
123-
unsigned long orig_gpr2;
123+
union {
124+
unsigned long orig_gpr2;
125+
unsigned long monitor_code;
126+
};
124127
union {
125128
struct {
126129
unsigned int int_code;

arch/s390/kernel/entry.S

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <asm/unistd.h>
2424
#include <asm/page.h>
2525
#include <asm/sigp.h>
26+
#include <asm/bug.h>
2627
#include <asm/irq.h>
2728
#include <asm/fpu-insn.h>
2829
#include <asm/setup.h>
@@ -173,6 +174,16 @@ SYM_FUNC_START(__switch_to_asm)
173174
BR_EX %r14
174175
SYM_FUNC_END(__switch_to_asm)
175176

177+
#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS)
178+
179+
SYM_FUNC_START(__WARN_trap)
180+
mc MONCODE_BUG_ARG(%r0),0
181+
BR_EX %r14
182+
SYM_FUNC_END(__WARN_trap)
183+
EXPORT_SYMBOL(__WARN_trap)
184+
185+
#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */
186+
176187
#if IS_ENABLED(CONFIG_KVM)
177188
/*
178189
* __sie64a calling convention:

arch/s390/kernel/traps.c

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/cpu.h>
2424
#include <linux/entry-common.h>
2525
#include <linux/kmsan.h>
26+
#include <linux/bug.h>
2627
#include <asm/asm-extable.h>
2728
#include <asm/irqflags.h>
2829
#include <asm/ptrace.h>
@@ -220,11 +221,48 @@ static void space_switch_exception(struct pt_regs *regs)
220221
do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
221222
}
222223

224+
#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS)
225+
226+
void *__warn_args(struct arch_va_list *args, struct pt_regs *regs)
227+
{
228+
struct stack_frame *stack_frame;
229+
230+
/*
231+
* Generate va_list from pt_regs. See ELF Application Binary Interface
232+
* s390x Supplement documentation for details.
233+
*
234+
* - __overflow_arg_area needs to point to the parameter area, which
235+
* is right above the standard stack frame (160 bytes)
236+
*
237+
* - __reg_save_area needs to point to a register save area where
238+
* general registers (%r2 - %r6) can be found at offset 16. Which
239+
* means that the gprs save area of pt_regs can be used
240+
*
241+
* - __gpr must be set to one, since the first parameter has been
242+
* processed (pointer to bug_entry)
243+
*/
244+
stack_frame = (struct stack_frame *)regs->gprs[15];
245+
args->__overflow_arg_area = stack_frame + 1;
246+
args->__reg_save_area = regs->gprs;
247+
args->__gpr = 1;
248+
return args;
249+
}
250+
251+
#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */
252+
223253
static void monitor_event_exception(struct pt_regs *regs)
224254
{
255+
enum bug_trap_type btt;
256+
225257
if (user_mode(regs))
226258
return;
227-
switch (report_bug(regs->psw.addr - (regs->int_code >> 16), regs)) {
259+
if (regs->monitor_code == MONCODE_BUG_ARG) {
260+
regs->psw.addr = regs->gprs[14];
261+
btt = report_bug_entry((struct bug_entry *)regs->gprs[2], regs);
262+
} else {
263+
btt = report_bug(regs->psw.addr - (regs->int_code >> 16), regs);
264+
}
265+
switch (btt) {
228266
case BUG_TRAP_TYPE_NONE:
229267
fixup_exception(regs);
230268
break;
@@ -258,11 +296,12 @@ static void __init test_monitor_call(void)
258296
if (!IS_ENABLED(CONFIG_BUG))
259297
return;
260298
asm_inline volatile(
261-
" mc 0,0\n"
299+
" mc %[monc](%%r0),0\n"
262300
"0: lhi %[val],0\n"
263301
"1:\n"
264302
EX_TABLE(0b, 1b)
265-
: [val] "+d" (val));
303+
: [val] "+d" (val)
304+
: [monc] "i" (MONCODE_BUG));
266305
if (!val)
267306
panic("Monitor call doesn't work!\n");
268307
}
@@ -297,6 +336,7 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
297336
teid.val = lc->trans_exc_code;
298337
regs->int_code = lc->pgm_int_code;
299338
regs->int_parm_long = teid.val;
339+
regs->monitor_code = lc->monitor_code;
300340
/*
301341
* In case of a guest fault, short-circuit the fault handler and return.
302342
* This way the sie64a() function will return 0; fault address and

0 commit comments

Comments
 (0)