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