]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/bug: Implement __WARN_printf()
authorHeiko Carstens <hca@linux.ibm.com>
Fri, 9 Jan 2026 15:31:41 +0000 (16:31 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Tue, 27 Jan 2026 11:16:16 +0000 (12:16 +0100)
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 <foo>:
 210:   c0 04 00 00 00 00       jgnop   210 <foo>
 216:   ec 26 00 06 00 7c       cgijne  %r2,0,222 <foo+0x12>
 21c:   c0 f4 00 00 00 00       jg      21c <foo+0xc>
                        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 <foo+0x28>
                        23a: R_390_PC32DBL      .LC48+0x2
 23e:   c0 e5 00 00 00 00       brasl   %r14,23e <foo+0x2e>
                        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 <foo+0x3e>
                        250: R_390_PC32DBL      __s390_indirect_jump_r14+0x2

With this change the generated code looks like this:

0000000000000210 <foo>:
 210:   c0 04 00 00 00 00       jgnop   210 <foo>
 216:   ec 26 00 06 00 7c       cgijne  %r2,0,222 <foo+0x12>
 21c:   c0 f4 00 00 00 00       jg      21c <foo+0xc>
                        21e: R_390_PC32DBL      __s390_indirect_jump_r14+0x2
 222:   c0 20 00 00 00 00       larl    %r2,222 <foobar+0x12>
                        224: R_390_PC32DBL      __bug_table+0x2
 228:   c0 f4 00 00 00 00       jg      228 <foobar+0x18>
                        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
          *000003ffe0f6a3b0af000001            mc      1,0
          >000003ffe0f6a3b4: 07fe                bcr     15,%r14
           000003ffe0f6a3b647000700            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 <svens@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/asm-prototypes.h
arch/s390/include/asm/bug.h
arch/s390/kernel/entry.S
arch/s390/kernel/traps.c

index f662eb4b9246fb5fc556403e655643ef6ba071d4..7bd1801cf241cba151a05cb8cedb60d83d0a0ab0 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/kvm_host.h>
 #include <linux/ftrace.h>
+#include <asm/bug.h>
 #include <asm/fpu.h>
 #include <asm/nospec-branch.h>
 #include <asm-generic/asm-prototypes.h>
index faa556226c0053c659bb4c15fa6bcfcf328b924d..1559873b19b0953a3e242fbcea30221be4b0a3e3 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/const.h>
 
 #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)
 #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__ */
index b7f1553d9ee5bac3cbe4c3fe65d69751a0e0044c..4873fe9d891ba2748c5bb5519c4b3b9ade92de64 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/unistd.h>
 #include <asm/page.h>
 #include <asm/sigp.h>
+#include <asm/bug.h>
 #include <asm/irq.h>
 #include <asm/fpu-insn.h>
 #include <asm/setup.h>
@@ -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:
index b2d6d7cc3b176d5fce21f8f8282f1bf28fb1ef82..2972f526cd8110604418d6b7e44a7fff403aea08 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/cpu.h>
 #include <linux/entry-common.h>
 #include <linux/kmsan.h>
+#include <linux/bug.h>
 #include <asm/asm-extable.h>
 #include <asm/irqflags.h>
 #include <asm/ptrace.h>
@@ -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;