From e5f3e67de587b8e876ca04d5bd021d751fe9c4d2 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:36 +0100 Subject: s390: Add CC_HAS_ASM_IMMEDIATE_STRINGS Upcoming changes to s390 specific inline assemblies require the usage of strings as immediate input operands. This works only with gcc-9 and newer compilers. With gcc-8 this leads to a compile error: void bar(void) { asm volatile("" :: "i" ("foo")); } Results in: In function 'bar': warning: asm operand 0 probably doesn't match constraints asm volatile("" :: "i" ("foo")); ^~~ error: impossible constraint in 'asm' Provide a CC_HAS_ASM_IMMEDIATE_STRINGS config option which allows to tell if the compiler supports strings as immediate input operands. Based on that conditional code can be provided. Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index cd856318ffe5..fcce8c5db703 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -69,6 +69,12 @@ config CC_HAS_ASM_AOR_FORMAT_FLAGS Clang versions before 19.1.0 do not support A, O, and R inline assembly format flags. +config CC_HAS_ASM_IMMEDIATE_STRINGS + def_bool !(CC_IS_GCC && GCC_VERSION < 90000) + help + GCC versions before 9.0.0 cannot handle strings as immediate + input operands in inline assemblies. + config CC_HAS_STACKPROTECTOR_GLOBAL def_bool $(cc-option, -mstack-protector-guard=global -mstack-protector-guard-record) -- cgit v1.2.3 From e3abd056ffc9d6397766817eadbd4297632aceaf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:37 +0100 Subject: s390/bug: Convert to inline assembly with input operands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite the bug inline assembly so it uses input operands again instead of pure macro replacements. This more or less reverts the conversion done when 'cond_str' support was added [1]. Reason for this is that the upcoming __WARN_printf() implementation requires an inline assembly with an output operand. At the same time input strings (format specifier and condition string) may contain the special '%' character. As soon as an inline assembly is specified to have input/output operands the '%' has a special meaning: e.g. converting the existing #define __BUG_FLAGS(cond_str, flags) \ asm_inline volatile(__stringify(ASM_BUG_FLAGS(cond_str, flags))); to #define __BUG_FLAGS(cond_str, flags) \ asm_inline volatile(__stringify(ASM_BUG_FLAGS(cond_str, flags))::); will result in a compile error as soon as 'cond_str' contains a '%' character: net/core/neighbour.c: In function ‘neigh_table_init’: ././include/linux/compiler_types.h:546:20: error: invalid 'asm': invalid %-code ... net/core/neighbour.c:1838:17: note: in expansion of macro ‘WARN_ON’ 1838 | WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN); | ^~~~~~~ Convert the code, use immediate operands, and also add comments similar to x86 which are emitted to the generated assembly file, which makes debugging much easier. Note: since gcc-8 does not support strings as immediate input operands, guard the new implementation with CC_HAS_ASM_IMMEDIATE_STRINGS and fallback to the generic non-exception based warning implementation for incompatible compilers. [1] 6584ff203aec ("bugs/s390: Use 'cond_str' in __EMIT_BUG()") Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/include/asm/bug.h | 73 +++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 42 deletions(-) diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index ee9221bb5d18..73f65d91da50 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -2,60 +2,49 @@ #ifndef _ASM_S390_BUG_H #define _ASM_S390_BUG_H -#include +#include -#ifdef CONFIG_BUG +#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS) -#ifndef CONFIG_DEBUG_BUGVERBOSE -#define _BUGVERBOSE_LOCATION(file, line) +#ifdef CONFIG_DEBUG_BUGVERBOSE +#define __BUG_ENTRY_VERBOSE(file, line) \ + " .long " file " - . # bug_entry::file\n" \ + " .short " line " # bug_entry::line\n" #else -#define __BUGVERBOSE_LOCATION(file, line) \ - .pushsection .rodata.str, "aMS", @progbits, 1; \ - .align 2; \ - 10002: .ascii file "\0"; \ - .popsection; \ - \ - .long 10002b - .; \ - .short line; -#define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line) +#define __BUG_ENTRY_VERBOSE(file, line) #endif -#ifndef CONFIG_GENERIC_BUG -#define __BUG_ENTRY(cond_str, flags) -#else -#define __BUG_ENTRY(cond_str, flags) \ - .pushsection __bug_table, "aw"; \ - .align 4; \ - 10000: .long 10001f - .; \ - _BUGVERBOSE_LOCATION(WARN_CONDITION_STR(cond_str) __FILE__, __LINE__) \ - .short flags; \ - .popsection; \ - 10001: -#endif - -#define ASM_BUG_FLAGS(cond_str, flags) \ - __BUG_ENTRY(cond_str, flags) \ - mc 0,0 - -#define ASM_BUG() ASM_BUG_FLAGS("", 0) - -#define __BUG_FLAGS(cond_str, flags) \ - asm_inline volatile(__stringify(ASM_BUG_FLAGS(cond_str, flags))); +#define __BUG_ASM(cond_str, flags) \ +do { \ + asm_inline volatile("\n" \ + "0: mc 0,0\n" \ + " .section __bug_table,\"aw\"\n" \ + "1: .long 0b - . # bug_entry::bug_addr\n" \ + __BUG_ENTRY_VERBOSE("%[file]", "%[line]") \ + " .short %[flgs] # bug_entry::flags\n" \ + " .org 1b+%[size]\n" \ + " .previous" \ + : \ + : [file] "i" (WARN_CONDITION_STR(cond_str) __FILE__), \ + [line] "i" (__LINE__), \ + [flgs] "i" (flags), \ + [size] "i" (sizeof(struct bug_entry))); \ +} while (0) -#define __WARN_FLAGS(cond_str, flags) \ -do { \ - __BUG_FLAGS(cond_str, BUGFLAG_WARNING|(flags)); \ +#define BUG() \ +do { \ + __BUG_ASM("", 0); \ + unreachable(); \ } while (0) -#define BUG() \ -do { \ - __BUG_FLAGS("", 0); \ - unreachable(); \ +#define __WARN_FLAGS(cond_str, flags) \ +do { \ + __BUG_ASM(cond_str, BUGFLAG_WARNING | (flags)); \ } while (0) #define HAVE_ARCH_BUG -#endif /* CONFIG_BUG */ +#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */ #include -- cgit v1.2.3 From 2b71b8ab971889edba278b71f1d3ff82cd42e175 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:38 +0100 Subject: s390/bug: Use BUG_FORMAT for DEBUG_BUGVERBOSE_DETAILED This is just the s390 variant of commit 4f1b701f24be ("x86/bug: Use BUG_FORMAT for DEBUG_BUGVERBOSE_DETAILED"). Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/include/asm/bug.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index 73f65d91da50..7e0498f22f2a 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -7,11 +7,18 @@ #if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS) #ifdef CONFIG_DEBUG_BUGVERBOSE -#define __BUG_ENTRY_VERBOSE(file, line) \ +#define __BUG_ENTRY_VERBOSE(format, file, line) \ + " .long " format " - . # bug_entry::format\n" \ " .long " file " - . # bug_entry::file\n" \ " .short " line " # bug_entry::line\n" #else -#define __BUG_ENTRY_VERBOSE(file, line) +#define __BUG_ENTRY_VERBOSE(format, file, line) +#endif + +#ifdef CONFIG_DEBUG_BUGVERBOSE_DETAILED +#define WARN_CONDITION_STR(cond_str) cond_str +#else +#define WARN_CONDITION_STR(cond_str) "" #endif #define __BUG_ASM(cond_str, flags) \ @@ -20,12 +27,13 @@ do { \ "0: mc 0,0\n" \ " .section __bug_table,\"aw\"\n" \ "1: .long 0b - . # bug_entry::bug_addr\n" \ - __BUG_ENTRY_VERBOSE("%[file]", "%[line]") \ + __BUG_ENTRY_VERBOSE("%[frmt]", "%[file]", "%[line]") \ " .short %[flgs] # bug_entry::flags\n" \ " .org 1b+%[size]\n" \ " .previous" \ : \ - : [file] "i" (WARN_CONDITION_STR(cond_str) __FILE__), \ + : [frmt] "i" (WARN_CONDITION_STR(cond_str)), \ + [file] "i" (__FILE__), \ [line] "i" (__LINE__), \ [flgs] "i" (flags), \ [size] "i" (sizeof(struct bug_entry))); \ @@ -43,6 +51,7 @@ do { \ } while (0) #define HAVE_ARCH_BUG +#define HAVE_ARCH_BUG_FORMAT #endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */ -- cgit v1.2.3 From 8cbfd13601af7d71bb86c2ea686489a6f139c0ba Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:39 +0100 Subject: s390/bug: Introduce and use monitor code macro The first operand address of the monitor call (mc) instruction is the monitor code. Currently the monitor code is ignored, but this will change. Therefore add and use MONCODE_BUG instead of a hardcoded zero. Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/include/asm/bug.h | 10 ++++++++-- arch/s390/kernel/traps.c | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index 7e0498f22f2a..faa556226c00 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -3,7 +3,11 @@ #define _ASM_S390_BUG_H #include +#include +#define MONCODE_BUG _AC(0, U) + +#ifndef __ASSEMBLER__ #if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS) #ifdef CONFIG_DEBUG_BUGVERBOSE @@ -24,7 +28,7 @@ #define __BUG_ASM(cond_str, flags) \ do { \ asm_inline volatile("\n" \ - "0: mc 0,0\n" \ + "0: mc %[monc](%%r0),0\n" \ " .section __bug_table,\"aw\"\n" \ "1: .long 0b - . # bug_entry::bug_addr\n" \ __BUG_ENTRY_VERBOSE("%[frmt]", "%[file]", "%[line]") \ @@ -32,7 +36,8 @@ do { \ " .org 1b+%[size]\n" \ " .previous" \ : \ - : [frmt] "i" (WARN_CONDITION_STR(cond_str)), \ + : [monc] "i" (MONCODE_BUG), \ + [frmt] "i" (WARN_CONDITION_STR(cond_str)), \ [file] "i" (__FILE__), \ [line] "i" (__LINE__), \ [flgs] "i" (flags), \ @@ -54,6 +59,7 @@ do { \ #define HAVE_ARCH_BUG_FORMAT #endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */ +#endif /* __ASSEMBLER__ */ #include diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 19687dab32f7..de63e98e724b 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -258,11 +258,12 @@ static void __init test_monitor_call(void) if (!IS_ENABLED(CONFIG_BUG)) return; asm_inline volatile( - " mc 0,0\n" + " mc %[monc](%%r0),0\n" "0: lhi %[val],0\n" "1:\n" EX_TABLE(0b, 1b) - : [val] "+d" (val)); + : [val] "+d" (val) + : [monc] "i" (MONCODE_BUG)); if (!val) panic("Monitor call doesn't work!\n"); } -- cgit v1.2.3 From ee44f4e7ebb56f1a2a3aaed8b01ea052fc225680 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:40 +0100 Subject: s390/traps: Copy monitor code to pt_regs In case of a monitor call program check the CPU stores the monitor code to lowcore. Let the program check handler copy it to the pt_regs structure so it can be used by the monitor call exception handler. Instead of increasing the pt_regs size add a union which contains both orig_gpr2 and monitor_code, since orig_gpr2 is not used in case of a program check. Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/include/asm/ptrace.h | 5 ++++- arch/s390/kernel/traps.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index e6ec0ccf3d73..aaceb1d9110a 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -120,7 +120,10 @@ struct pt_regs { unsigned long gprs[NUM_GPRS]; }; }; - unsigned long orig_gpr2; + union { + unsigned long orig_gpr2; + unsigned long monitor_code; + }; union { struct { unsigned int int_code; diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index de63e98e724b..b2d6d7cc3b17 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -298,6 +298,7 @@ void noinstr __do_pgm_check(struct pt_regs *regs) teid.val = lc->trans_exc_code; regs->int_code = lc->pgm_int_code; regs->int_parm_long = teid.val; + regs->monitor_code = lc->monitor_code; /* * In case of a guest fault, short-circuit the fault handler and return. * This way the sie64a() function will return 0; fault address and -- cgit v1.2.3 From 04dabb4261c387318affbdb22c15c31138a989f5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:41 +0100 Subject: s390/bug: Implement __WARN_printf() This is the s390 variant of commit 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()"). See the x86 commit for the general idea; there are only implementation details which are different. With the new exception based __WARN_printf() implementation the generated code for a simple WARN() is simplified. For example: void foo(int a) { WARN(a, "bar"); } Before this change the generated code looks like this: 0000000000000210 : 210: c0 04 00 00 00 00 jgnop 210 216: ec 26 00 06 00 7c cgijne %r2,0,222 21c: c0 f4 00 00 00 00 jg 21c 21e: R_390_PC32DBL __s390_indirect_jump_r14+0x2 222: eb ef f0 88 00 24 stmg %r14,%r15,136(%r15) 228: b9 04 00 ef lgr %r14,%r15 22c: e3 f0 ff e8 ff 71 lay %r15,-24(%r15) 232: e3 e0 f0 98 00 24 stg %r14,152(%r15) 238: c0 20 00 00 00 00 larl %r2,238 23a: R_390_PC32DBL .LC48+0x2 23e: c0 e5 00 00 00 00 brasl %r14,23e 240: R_390_PLT32DBL __warn_printk+0x2 244: af 00 00 00 mc 0,0 248: eb ef f0 a0 00 04 lmg %r14,%r15,160(%r15) 24e: c0 f4 00 00 00 00 jg 24e 250: R_390_PC32DBL __s390_indirect_jump_r14+0x2 With this change the generated code looks like this: 0000000000000210 : 210: c0 04 00 00 00 00 jgnop 210 216: ec 26 00 06 00 7c cgijne %r2,0,222 21c: c0 f4 00 00 00 00 jg 21c 21e: R_390_PC32DBL __s390_indirect_jump_r14+0x2 222: c0 20 00 00 00 00 larl %r2,222 224: R_390_PC32DBL __bug_table+0x2 228: c0 f4 00 00 00 00 jg 228 22a: R_390_PLT32DBL __WARN_trap+0x2 Downside is that the call trace now starts at __WARN_trap(): ------------[ cut here ]------------ bar WARNING: arch/s390/kernel/setup.c:1017 at 0x0, CPU#0: swapper/0/0 ... Krnl PSW : 0704c00180000000 000003ffe0f6a3b4 (__WARN_trap+0x4/0x10) ... Krnl Code: 000003ffe0f6a3ac: 0707 bcr 0,%r7 000003ffe0f6a3ae: 0707 bcr 0,%r7 *000003ffe0f6a3b0: af000001 mc 1,0 >000003ffe0f6a3b4: 07fe bcr 15,%r14 000003ffe0f6a3b6: 47000700 bc 0,1792 000003ffe0f6a3ba: 0707 bcr 0,%r7 000003ffe0f6a3bc: 0707 bcr 0,%r7 000003ffe0f6a3be: 0707 bcr 0,%r7 Call Trace: [<000003ffe0f6a3b4>] __WARN_trap+0x4/0x10 ([<000003ffe185a54c>] start_kernel+0x53c/0x5d8) [<000003ffe010002e>] startup_continue+0x2e/0x40 Which isn't too helpful. This can be addressed by just skipping __WARN_trap(), which will be addressed in a later patch. Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/include/asm/asm-prototypes.h | 1 + arch/s390/include/asm/bug.h | 62 ++++++++++++++++++++++++++++++---- arch/s390/kernel/entry.S | 11 ++++++ arch/s390/kernel/traps.c | 38 ++++++++++++++++++++- 4 files changed, 105 insertions(+), 7 deletions(-) diff --git a/arch/s390/include/asm/asm-prototypes.h b/arch/s390/include/asm/asm-prototypes.h index f662eb4b9246..7bd1801cf241 100644 --- a/arch/s390/include/asm/asm-prototypes.h +++ b/arch/s390/include/asm/asm-prototypes.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index faa556226c00..1559873b19b0 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -6,6 +6,7 @@ #include #define MONCODE_BUG _AC(0, U) +#define MONCODE_BUG_ARG _AC(1, U) #ifndef __ASSEMBLER__ #if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS) @@ -25,16 +26,20 @@ #define WARN_CONDITION_STR(cond_str) "" #endif +#define __BUG_ENTRY(format, file, line, flags, size) \ + " .section __bug_table,\"aw\"\n" \ + "1: .long 0b - . # bug_entry::bug_addr\n" \ + __BUG_ENTRY_VERBOSE(format, file, line) \ + " .short "flags" # bug_entry::flags\n" \ + " .org 1b+"size"\n" \ + " .previous" + #define __BUG_ASM(cond_str, flags) \ do { \ asm_inline volatile("\n" \ "0: mc %[monc](%%r0),0\n" \ - " .section __bug_table,\"aw\"\n" \ - "1: .long 0b - . # bug_entry::bug_addr\n" \ - __BUG_ENTRY_VERBOSE("%[frmt]", "%[file]", "%[line]") \ - " .short %[flgs] # bug_entry::flags\n" \ - " .org 1b+%[size]\n" \ - " .previous" \ + __BUG_ENTRY("%[frmt]", "%[file]", "%[line]", \ + "%[flgs]", "%[size]") \ : \ : [monc] "i" (MONCODE_BUG), \ [frmt] "i" (WARN_CONDITION_STR(cond_str)), \ @@ -55,8 +60,53 @@ do { \ __BUG_ASM(cond_str, BUGFLAG_WARNING | (flags)); \ } while (0) +#define __WARN_bug_entry(flags, format) \ +({ \ + struct bug_entry *bug; \ + \ + asm_inline volatile("\n" \ + "0: larl %[bug],1f\n" \ + __BUG_ENTRY("%[frmt]", "%[file]", "%[line]", \ + "%[flgs]", "%[size]") \ + : [bug] "=d" (bug) \ + : [frmt] "i" (format), \ + [file] "i" (__FILE__), \ + [line] "i" (__LINE__), \ + [flgs] "i" (flags), \ + [size] "i" (sizeof(struct bug_entry))); \ + bug; \ +}) + +/* + * Variable Argument List (va_list) as defined in ELF Application + * Binary Interface s390x Supplement documentation. + */ +struct arch_va_list { + long __gpr; + long __fpr; + void *__overflow_arg_area; + void *__reg_save_area; +}; + +struct bug_entry; +struct pt_regs; + +void *__warn_args(struct arch_va_list *args, struct pt_regs *regs); +void __WARN_trap(struct bug_entry *bug, ...); + +#define __WARN_print_arg(flags, format, arg...) \ +do { \ + int __flags = (flags) | BUGFLAG_WARNING | BUGFLAG_ARGS; \ + \ + __WARN_trap(__WARN_bug_entry(__flags, format), ## arg); \ +} while (0) + +#define __WARN_printf(taint, fmt, arg...) \ + __WARN_print_arg(BUGFLAG_TAINT(taint), fmt, ## arg) + #define HAVE_ARCH_BUG #define HAVE_ARCH_BUG_FORMAT +#define HAVE_ARCH_BUG_FORMAT_ARGS #endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */ #endif /* __ASSEMBLER__ */ diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index b7f1553d9ee5..4873fe9d891b 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -173,6 +174,16 @@ SYM_FUNC_START(__switch_to_asm) BR_EX %r14 SYM_FUNC_END(__switch_to_asm) +#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS) + +SYM_FUNC_START(__WARN_trap) + mc MONCODE_BUG_ARG(%r0),0 + BR_EX %r14 +SYM_FUNC_END(__WARN_trap) +EXPORT_SYMBOL(__WARN_trap) + +#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */ + #if IS_ENABLED(CONFIG_KVM) /* * __sie64a calling convention: diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index b2d6d7cc3b17..2972f526cd81 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -220,11 +221,46 @@ static void space_switch_exception(struct pt_regs *regs) do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); } +#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS) + +void *__warn_args(struct arch_va_list *args, struct pt_regs *regs) +{ + struct stack_frame *stack_frame; + + /* + * Generate va_list from pt_regs. See ELF Application Binary Interface + * s390x Supplement documentation for details. + * + * - __overflow_arg_area needs to point to the parameter area, which + * is right above the standard stack frame (160 bytes) + * + * - __reg_save_area needs to point to a register save area where + * general registers (%r2 - %r6) can be found at offset 16. Which + * means that the gprs save area of pt_regs can be used + * + * - __gpr must be set to one, since the first parameter has been + * processed (pointer to bug_entry) + */ + stack_frame = (struct stack_frame *)regs->gprs[15]; + args->__overflow_arg_area = stack_frame + 1; + args->__reg_save_area = regs->gprs; + args->__gpr = 1; + return args; +} + +#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */ + static void monitor_event_exception(struct pt_regs *regs) { + enum bug_trap_type btt; + if (user_mode(regs)) return; - switch (report_bug(regs->psw.addr - (regs->int_code >> 16), regs)) { + if (regs->monitor_code == MONCODE_BUG_ARG) + btt = report_bug_entry((struct bug_entry *)regs->gprs[2], regs); + else + btt = report_bug(regs->psw.addr - (regs->int_code >> 16), regs); + switch (btt) { case BUG_TRAP_TYPE_NONE: fixup_exception(regs); break; -- cgit v1.2.3 From 940cfea4270436edf515bf07d0a778eed6cec16d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:42 +0100 Subject: s390/bug: Implement WARN_ONCE() This is the s390 variant of commit 11bb4944f014 ("x86/bug: Implement WARN_ONCE()"). Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/include/asm/bug.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index 1559873b19b0..1fbcbdbc595f 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -104,6 +104,17 @@ do { \ #define __WARN_printf(taint, fmt, arg...) \ __WARN_print_arg(BUGFLAG_TAINT(taint), fmt, ## arg) +#define WARN_ONCE(cond, format, arg...) \ +({ \ + int __ret_warn_on = !!(cond); \ + \ + if (unlikely(__ret_warn_on)) { \ + __WARN_print_arg(BUGFLAG_ONCE|BUGFLAG_TAINT(TAINT_WARN),\ + format, ## arg); \ + } \ + __ret_warn_on; \ +}) + #define HAVE_ARCH_BUG #define HAVE_ARCH_BUG_FORMAT #define HAVE_ARCH_BUG_FORMAT_ARGS -- cgit v1.2.3 From 79996065cfa258de95c123ca9ed93754ab60d8c8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:43 +0100 Subject: s390/bug: Skip __WARN_trap() in call traces In order to avoid rather pointless warning disassemblies of __WARN_trap() set the PSW address to the return address of the function which called __WARN_trap(). This is the address to which __WARN_trap() would return in any case. The result is a disassembly of the function which called __WARN_trap(), which is much more helpful. Before: WARNING: arch/s390/kernel/setup.c:1017 at foobar+0x2c/0x20, CPU#0: swapper/0/0 ... Krnl PSW : 0704c00180000000 000003ffe0f675f4 (__WARN_trap+0x4/0x10) ... Krnl Code: 000003ffe0f675ec: 0707 bcr 0,%r7 000003ffe0f675ee: 0707 bcr 0,%r7 *000003ffe0f675f0: af000001 mc 1,0 >000003ffe0f675f4: 07fe bcr 15,%r14 000003ffe0f675f6: 47000700 bc 0,1792 000003ffe0f675fa: 0707 bcr 0,%r7 000003ffe0f675fc: 0707 bcr 0,%r7 000003ffe0f675fe: 0707 bcr 0,%r7 Call Trace: [<000003ffe0f675f4>] __WARN_trap+0x4/0x10 [<000003ffe185bc2e>] arch_cpu_finalize_init+0x26/0x60 [<000003ffe185654c>] start_kernel+0x53c/0x5d8 [<000003ffe010002e>] startup_continue+0x2e/0x40 Afterwards: WARNING: arch/s390/kernel/setup.c:1017 at foobar+0x12/0x30, CPU#0: swapper/0/0 ... Krnl PSW : 0704c00180000000 000003ffe185bc2e (arch_cpu_finalize_init+0x26/0x60) ... Krnl Code: 000003ffe185bc1c: e3f0ff98ff71 lay %r15,-104(%r15) 000003ffe185bc22: e3e0f0980024 stg %r14,152(%r15) *000003ffe185bc28: c0e5ff45ed94 brasl %r14,000003ffe0119750 >000003ffe185bc2e: c0e5ffa052b9 brasl %r14,000003ffe0c661a0 000003ffe185bc34: c020fffe86d6 larl %r2,000003ffe182c9e0 000003ffe185bc3a: e548f0a80006 mvghi 168(%r15),6 000003ffe185bc40: e548f0a00005 mvghi 160(%r15),5 000003ffe185bc46: a7690004 lghi %r6,4 Call Trace: [<000003ffe185bc2e>] arch_cpu_finalize_init+0x26/0x60 [<000003ffe185654c>] start_kernel+0x53c/0x5d8 [<000003ffe010002e>] startup_continue+0x2e/0x40 Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/kernel/traps.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 2972f526cd81..1b5c6fc431cc 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -256,10 +256,12 @@ static void monitor_event_exception(struct pt_regs *regs) if (user_mode(regs)) return; - if (regs->monitor_code == MONCODE_BUG_ARG) + if (regs->monitor_code == MONCODE_BUG_ARG) { + regs->psw.addr = regs->gprs[14]; btt = report_bug_entry((struct bug_entry *)regs->gprs[2], regs); - else + } else { btt = report_bug(regs->psw.addr - (regs->int_code >> 16), regs); + } switch (btt) { case BUG_TRAP_TYPE_NONE: fixup_exception(regs); -- cgit v1.2.3 From 9f9d68c308cb63de67d35171925ce3875d076d4f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 9 Jan 2026 16:31:44 +0100 Subject: s390/bug: Prevent tail-call optimization For the exception based __WARN_trap() implementation it is technically not necessary to prevent tail-call optimization, however it may be confusing to see warning messages like: WARNING: arch/s390/kernel/setup.c:1017 at foobar+0x2c/0x50, CPU#0: swapper/0/0 together with a disassembly of a different function caused by tail-call optimization for the __WARN_trap() call. Prevent that by adding an empty asm statement. This generates slightly worse code, but should hopefully avoid confusion. With this the output looks like: WARNING: arch/s390/kernel/setup.c:1017 at foobar+0x2c/0x50, CPU#0: swapper/0/0 ... Krnl PSW : 0704c00180000000 000003ffe0119788 (foobar+0x38/0x50) ... Krnl Code: 000003ffe0119776: e3e0f0980024 stg %r14,152(%r15) 000003ffe011977c: c02000b8992a larl %r2,000003ffe182c9d0 *000003ffe0119782: c0e5007270b7 brasl %r14,000003ffe0f678f0 >000003ffe0119788: ebeff0a00004 lmg %r14,%r15,160(%r15) 000003ffe011978e: 07fe bcr 15,%r14 000003ffe0119790: 47000700 bc 0,1792 000003ffe0119794: 0707 bcr 0,%r7 000003ffe0119796: 0707 bcr 0,%r7 Call Trace: [<000003ffe0119788>] foobar+0x38/0x50 [<000003ffe185bc2e>] arch_cpu_finalize_init+0x26/0x60 [<000003ffe185654c>] start_kernel+0x53c/0x5d8 [<000003ffe010002e>] startup_continue+0x2e/0x40 A better solution would be to replace or patch the branch instruction to __WARN_trap() with the monitor call instruction, similar to what is done for x86 [1]. However s390 does not support static_cond_calls(). Therefore use the simple approach for the time being. [1] commit 860238af7a33 ("x86_64/bug: Inline the UD1") Reviewed-by: Sven Schnelle Signed-off-by: Heiko Carstens --- arch/s390/include/asm/bug.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index 1fbcbdbc595f..59017fd3d935 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -99,6 +99,8 @@ do { \ int __flags = (flags) | BUGFLAG_WARNING | BUGFLAG_ARGS; \ \ __WARN_trap(__WARN_bug_entry(__flags, format), ## arg); \ + /* prevent tail-call optimization */ \ + asm(""); \ } while (0) #define __WARN_printf(taint, fmt, arg...) \ -- cgit v1.2.3