1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_X86_BUG_H
3#define _ASM_X86_BUG_H
4
5#include <linux/stringify.h>
6#include <linux/instrumentation.h>
7#include <linux/objtool.h>
8#include <asm/asm.h>
9
10/*
11 * Despite that some emulators terminate on UD2, we use it for WARN().
12 */
13#define ASM_UD2 _ASM_BYTES(0x0f, 0x0b)
14#define INSN_UD2 0x0b0f
15#define LEN_UD2 2
16
17#define ASM_UDB _ASM_BYTES(0xd6)
18#define INSN_UDB 0xd6
19#define LEN_UDB 1
20
21/*
22 * In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
23 */
24#define INSN_ASOP 0x67
25#define INSN_LOCK 0xf0
26#define OPCODE_ESCAPE 0x0f
27#define SECOND_BYTE_OPCODE_UD1 0xb9
28#define SECOND_BYTE_OPCODE_UD2 0x0b
29
30#define BUG_NONE 0xffff
31#define BUG_UD2 0xfffe
32#define BUG_UD1 0xfffd
33#define BUG_UD1_UBSAN 0xfffc
34#define BUG_UDB 0xffd6
35#define BUG_LOCK 0xfff0
36
37#ifdef CONFIG_GENERIC_BUG
38
39#ifdef CONFIG_X86_32
40# define __BUG_REL(val) ".long " val
41#else
42# define __BUG_REL(val) ".long " val " - ."
43#endif
44
45#ifdef CONFIG_DEBUG_BUGVERBOSE
46#define __BUG_ENTRY(file, line, flags) \
47 "2:\t" __BUG_REL("1b") "\t# bug_entry::bug_addr\n" \
48 "\t" __BUG_REL(file) "\t# bug_entry::file\n" \
49 "\t.word " line "\t# bug_entry::line\n" \
50 "\t.word " flags "\t# bug_entry::flags\n"
51#else
52#define __BUG_ENTRY(file, line, flags) \
53 "2:\t" __BUG_REL("1b") "\t# bug_entry::bug_addr\n" \
54 "\t.word " flags "\t# bug_entry::flags\n"
55#endif
56
57#define _BUG_FLAGS_ASM(ins, file, line, flags, size, extra) \
58 "1:\t" ins "\n" \
59 ".pushsection __bug_table,\"aw\"\n" \
60 __BUG_ENTRY(file, line, flags) \
61 "\t.org 2b + " size "\n" \
62 ".popsection\n" \
63 extra
64
65#define _BUG_FLAGS(ins, flags, extra) \
66do { \
67 asm_inline volatile(_BUG_FLAGS_ASM(ins, "%c0", \
68 "%c1", "%c2", "%c3", extra) \
69 : : "i" (__FILE__), "i" (__LINE__), \
70 "i" (flags), \
71 "i" (sizeof(struct bug_entry))); \
72} while (0)
73
74#define ARCH_WARN_ASM(file, line, flags, size) \
75 _BUG_FLAGS_ASM(ASM_UD2, file, line, flags, size, "")
76
77#else
78
79#define _BUG_FLAGS(ins, flags, extra) asm volatile(ins)
80
81#endif /* CONFIG_GENERIC_BUG */
82
83#define HAVE_ARCH_BUG
84#define BUG() \
85do { \
86 instrumentation_begin(); \
87 _BUG_FLAGS(ASM_UD2, 0, ""); \
88 __builtin_unreachable(); \
89} while (0)
90
91/*
92 * This instrumentation_begin() is strictly speaking incorrect; but it
93 * suppresses the complaints from WARN()s in noinstr code. If such a WARN()
94 * were to trigger, we'd rather wreck the machine in an attempt to get the
95 * message out than not know about it.
96 */
97
98#define ARCH_WARN_REACHABLE ANNOTATE_REACHABLE(1b)
99
100#define __WARN_FLAGS(flags) \
101do { \
102 __auto_type __flags = BUGFLAG_WARNING|(flags); \
103 instrumentation_begin(); \
104 _BUG_FLAGS(ASM_UD2, __flags, ARCH_WARN_REACHABLE); \
105 instrumentation_end(); \
106} while (0)
107
108#include <asm-generic/bug.h>
109
110#endif /* _ASM_X86_BUG_H */
111