1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_POWERPC_BUG_H
3#define _ASM_POWERPC_BUG_H
4#ifdef __KERNEL__
5
6#include <asm/asm-compat.h>
7#include <asm/extable.h>
8
9#ifdef CONFIG_BUG
10
11#ifdef __ASSEMBLY__
12#include <asm/asm-offsets.h>
13#ifdef CONFIG_DEBUG_BUGVERBOSE
14.macro EMIT_BUG_ENTRY addr,file,line,flags
15	 .section __bug_table,"aw"
165001:	 .4byte \addr - 5001b, 5002f - 5001b
17	 .short \line, \flags
18	 .org 5001b+BUG_ENTRY_SIZE
19	 .previous
20	 .section .rodata,"a"
215002:	 .asciz "\file"
22	 .previous
23.endm
24#else
25.macro EMIT_BUG_ENTRY addr,file,line,flags
26	 .section __bug_table,"aw"
275001:	 .4byte \addr - 5001b
28	 .short \flags
29	 .org 5001b+BUG_ENTRY_SIZE
30	 .previous
31.endm
32#endif /* verbose */
33
34.macro EMIT_WARN_ENTRY addr,file,line,flags
35	EX_TABLE(\addr,\addr+4)
36	EMIT_BUG_ENTRY \addr,\file,\line,\flags
37.endm
38
39#else /* !__ASSEMBLY__ */
40/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
41   sizeof(struct bug_entry), respectively */
42#ifdef CONFIG_DEBUG_BUGVERBOSE
43#define _EMIT_BUG_ENTRY				\
44	".section __bug_table,\"aw\"\n"		\
45	"2:\t.4byte 1b - 2b, %0 - 2b\n"		\
46	"\t.short %1, %2\n"			\
47	".org 2b+%3\n"				\
48	".previous\n"
49#else
50#define _EMIT_BUG_ENTRY				\
51	".section __bug_table,\"aw\"\n"		\
52	"2:\t.4byte 1b - 2b\n"			\
53	"\t.short %2\n"				\
54	".org 2b+%3\n"				\
55	".previous\n"
56#endif
57
58#define BUG_ENTRY(insn, flags, ...)			\
59	__asm__ __volatile__(				\
60		"1:	" insn "\n"			\
61		_EMIT_BUG_ENTRY				\
62		: : "i" (__FILE__), "i" (__LINE__),	\
63		  "i" (flags),				\
64		  "i" (sizeof(struct bug_entry)),	\
65		  ##__VA_ARGS__)
66
67#define WARN_ENTRY(insn, flags, label, ...)		\
68	asm_volatile_goto(				\
69		"1:	" insn "\n"			\
70		EX_TABLE(1b, %l[label])			\
71		_EMIT_BUG_ENTRY				\
72		: : "i" (__FILE__), "i" (__LINE__),	\
73		  "i" (flags),				\
74		  "i" (sizeof(struct bug_entry)),	\
75		  ##__VA_ARGS__ : : label)
76
77/*
78 * BUG_ON() and WARN_ON() do their best to cooperate with compile-time
79 * optimisations. However depending on the complexity of the condition
80 * some compiler versions may not produce optimal results.
81 */
82
83#define BUG() do {						\
84	BUG_ENTRY("twi 31, 0, 0", 0);				\
85	unreachable();						\
86} while (0)
87#define HAVE_ARCH_BUG
88
89#define __WARN_FLAGS(flags) do {				\
90	__label__ __label_warn_on;				\
91								\
92	WARN_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags), __label_warn_on); \
93	unreachable();						\
94								\
95__label_warn_on:						\
96	break;							\
97} while (0)
98
99#ifdef CONFIG_PPC64
100#define BUG_ON(x) do {						\
101	if (__builtin_constant_p(x)) {				\
102		if (x)						\
103			BUG();					\
104	} else {						\
105		BUG_ENTRY(PPC_TLNEI " %4, 0", 0, "r" ((__force long)(x)));	\
106	}							\
107} while (0)
108
109#define WARN_ON(x) ({						\
110	bool __ret_warn_on = false;				\
111	do {							\
112		if (__builtin_constant_p((x))) {		\
113			if (!(x)) 				\
114				break; 				\
115			__WARN();				\
116			__ret_warn_on = true;			\
117		} else {					\
118			__label__ __label_warn_on;		\
119								\
120			WARN_ENTRY(PPC_TLNEI " %4, 0",		\
121				   BUGFLAG_WARNING | BUGFLAG_TAINT(TAINT_WARN),	\
122				   __label_warn_on,		\
123				   "r" ((__force long)(x)));	\
124			break;					\
125__label_warn_on:						\
126			__ret_warn_on = true;			\
127		}						\
128	} while (0);						\
129	unlikely(__ret_warn_on);				\
130})
131
132#define HAVE_ARCH_BUG_ON
133#define HAVE_ARCH_WARN_ON
134#endif
135
136#endif /* __ASSEMBLY __ */
137#else
138#ifdef __ASSEMBLY__
139.macro EMIT_BUG_ENTRY addr,file,line,flags
140.endm
141.macro EMIT_WARN_ENTRY addr,file,line,flags
142.endm
143#else /* !__ASSEMBLY__ */
144#define _EMIT_BUG_ENTRY
145#define _EMIT_WARN_ENTRY
146#endif
147#endif /* CONFIG_BUG */
148
149#include <asm-generic/bug.h>
150
151#ifndef __ASSEMBLY__
152
153struct pt_regs;
154void hash__do_page_fault(struct pt_regs *);
155void bad_page_fault(struct pt_regs *, int);
156extern void _exception(int, struct pt_regs *, int, unsigned long);
157extern void _exception_pkey(struct pt_regs *, unsigned long, int);
158extern void die(const char *, struct pt_regs *, long);
159void die_mce(const char *str, struct pt_regs *regs, long err);
160extern bool die_will_crash(void);
161extern void panic_flush_kmsg_start(void);
162extern void panic_flush_kmsg_end(void);
163#endif /* !__ASSEMBLY__ */
164
165#endif /* __KERNEL__ */
166#endif /* _ASM_POWERPC_BUG_H */
167