From: Heiko Carstens Date: Fri, 9 Jan 2026 15:31:41 +0000 (+0100) Subject: s390/bug: Implement __WARN_printf() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=04dabb4261c387318affbdb22c15c31138a989f5;p=thirdparty%2Fkernel%2Flinux.git 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 --- diff --git a/arch/s390/include/asm/asm-prototypes.h b/arch/s390/include/asm/asm-prototypes.h index f662eb4b9246f..7bd1801cf241c 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 faa556226c005..1559873b19b09 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 b7f1553d9ee5b..4873fe9d891ba 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 b2d6d7cc3b176..2972f526cd811 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;