#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)), \
__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__ */
#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>
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;