Commit 1e688dd2 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman
Browse files

powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with asm goto



Using asm goto in __WARN_FLAGS() and WARN_ON() allows more
flexibility to GCC.

For that add an entry to the exception table so that
program_check_exception() knowns where to resume execution
after a WARNING.

Here are two exemples. The first one is done on PPC32 (which
benefits from the previous patch), the second is on PPC64.

	unsigned long test(struct pt_regs *regs)
	{
		int ret;

		WARN_ON(regs->msr & MSR_PR);

		return regs->gpr[3];
	}

	unsigned long test9w(unsigned long a, unsigned long b)
	{
		if (WARN_ON(!b))
			return 0;
		return a / b;
	}

Before the patch:

	000003a8 <test>:
	 3a8:	81 23 00 84 	lwz     r9,132(r3)
	 3ac:	71 29 40 00 	andi.   r9,r9,16384
	 3b0:	40 82 00 0c 	bne     3bc <test+0x14>
	 3b4:	80 63 00 0c 	lwz     r3,12(r3)
	 3b8:	4e 80 00 20 	blr

	 3bc:	0f e0 00 00 	twui    r0,0
	 3c0:	80 63 00 0c 	lwz     r3,12(r3)
	 3c4:	4e 80 00 20 	blr

	0000000000000bf0 <.test9w>:
	 bf0:	7c 89 00 74 	cntlzd  r9,r4
	 bf4:	79 29 d1 82 	rldicl  r9,r9,58,6
	 bf8:	0b 09 00 00 	tdnei   r9,0
	 bfc:	2c 24 00 00 	cmpdi   r4,0
	 c00:	41 82 00 0c 	beq     c0c <.test9w+0x1c>
	 c04:	7c 63 23 92 	divdu   r3,r3,r4
	 c08:	4e 80 00 20 	blr

	 c0c:	38 60 00 00 	li      r3,0
	 c10:	4e 80 00 20 	blr

After the patch:

	000003a8 <test>:
	 3a8:	81 23 00 84 	lwz     r9,132(r3)
	 3ac:	71 29 40 00 	andi.   r9,r9,16384
	 3b0:	40 82 00 0c 	bne     3bc <test+0x14>
	 3b4:	80 63 00 0c 	lwz     r3,12(r3)
	 3b8:	4e 80 00 20 	blr

	 3bc:	0f e0 00 00 	twui    r0,0

	0000000000000c50 <.test9w>:
	 c50:	7c 89 00 74 	cntlzd  r9,r4
	 c54:	79 29 d1 82 	rldicl  r9,r9,58,6
	 c58:	0b 09 00 00 	tdnei   r9,0
	 c5c:	7c 63 23 92 	divdu   r3,r3,r4
	 c60:	4e 80 00 20 	blr

	 c70:	38 60 00 00 	li      r3,0
	 c74:	4e 80 00 20 	blr

In the first exemple, we see GCC doesn't need to duplicate what
happens after the trap.

In the second exemple, we see that GCC doesn't need to emit a test
and a branch in the likely path in addition to the trap.

We've got some WARN_ON() in .softirqentry.text section so it needs
to be added in the OTHER_TEXT_SECTIONS in modpost.c

Signed-off-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/389962b1b702e3c78d169e59bcfac56282889173.1618331882.git.christophe.leroy@csgroup.eu
parent db87a719
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@
	/* Prevent access to userspace using any key values */
	LOAD_REG_IMMEDIATE(\gpr2, AMR_KUAP_BLOCKED)
999:	tdne	\gpr1, \gpr2
	EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
	EMIT_WARN_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
	END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_BOOK3S_KUAP, 67)
#endif
.endm
+45 −9
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#ifdef __KERNEL__

#include <asm/asm-compat.h>
#include <asm/extable.h>

#ifdef CONFIG_BUG

@@ -30,6 +31,11 @@
.endm
#endif /* verbose */

.macro EMIT_WARN_ENTRY addr,file,line,flags
	EX_TABLE(\addr,\addr+4)
	EMIT_BUG_ENTRY \addr,\file,\line,\flags
.endm

#else /* !__ASSEMBLY__ */
/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
   sizeof(struct bug_entry), respectively */
@@ -58,6 +64,16 @@
		  "i" (sizeof(struct bug_entry)),	\
		  ##__VA_ARGS__)

#define WARN_ENTRY(insn, flags, label, ...)		\
	asm_volatile_goto(				\
		"1:	" insn "\n"			\
		EX_TABLE(1b, %l[label])			\
		_EMIT_BUG_ENTRY				\
		: : "i" (__FILE__), "i" (__LINE__),	\
		  "i" (flags),				\
		  "i" (sizeof(struct bug_entry)),	\
		  ##__VA_ARGS__ : : label)

/*
 * BUG_ON() and WARN_ON() do their best to cooperate with compile-time
 * optimisations. However depending on the complexity of the condition
@@ -70,7 +86,15 @@
} while (0)
#define HAVE_ARCH_BUG

#define __WARN_FLAGS(flags) BUG_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags))
#define __WARN_FLAGS(flags) do {				\
	__label__ __label_warn_on;				\
								\
	WARN_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags), __label_warn_on); \
	unreachable();						\
								\
__label_warn_on:						\
	break;							\
} while (0)

#ifdef CONFIG_PPC64
#define BUG_ON(x) do {						\
@@ -83,15 +107,24 @@
} while (0)

#define WARN_ON(x) ({						\
	int __ret_warn_on = !!(x);				\
	if (__builtin_constant_p(__ret_warn_on)) {		\
		if (__ret_warn_on)				\
	bool __ret_warn_on = false;				\
	do {							\
		if (__builtin_constant_p((x))) {		\
			if (!(x)) 				\
				break; 				\
			__WARN();				\
			__ret_warn_on = true;			\
		} else {					\
		BUG_ENTRY(PPC_TLNEI " %4, 0",			\
			__label__ __label_warn_on;		\
								\
			WARN_ENTRY(PPC_TLNEI " %4, 0",		\
				   BUGFLAG_WARNING | BUGFLAG_TAINT(TAINT_WARN),	\
			  "r" (__ret_warn_on));	\
				   __label_warn_on, "r" (x));	\
			break;					\
__label_warn_on:						\
			__ret_warn_on = true;			\
		}						\
	} while (0);						\
	unlikely(__ret_warn_on);				\
})

@@ -104,8 +137,11 @@
#ifdef __ASSEMBLY__
.macro EMIT_BUG_ENTRY addr,file,line,flags
.endm
.macro EMIT_WARN_ENTRY addr,file,line,flags
.endm
#else /* !__ASSEMBLY__ */
#define _EMIT_BUG_ENTRY
#define _EMIT_WARN_ENTRY
#endif
#endif /* CONFIG_BUG */

+14 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

#define ARCH_HAS_RELATIVE_EXTABLE

#ifndef __ASSEMBLY__

struct exception_table_entry {
	int insn;
	int fixup;
@@ -28,3 +30,15 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
}

#endif

/*
 * Helper macro for exception table entries
 */
#define EX_TABLE(_fault, _target)		\
	stringify_in_c(.section __ex_table,"a";)\
	stringify_in_c(.balign 4;)		\
	stringify_in_c(.long (_fault) - . ;)	\
	stringify_in_c(.long (_target) - . ;)	\
	stringify_in_c(.previous)

#endif
+1 −10
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <asm/ppc-opcode.h>
#include <asm/firmware.h>
#include <asm/feature-fixups.h>
#include <asm/extable.h>

#ifdef __ASSEMBLY__

@@ -752,16 +753,6 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)

#endif /*  __ASSEMBLY__ */

/*
 * Helper macro for exception table entries
 */
#define EX_TABLE(_fault, _target)		\
	stringify_in_c(.section __ex_table,"a";)\
	stringify_in_c(.balign 4;)		\
	stringify_in_c(.long (_fault) - . ;)	\
	stringify_in_c(.long (_target) - . ;)	\
	stringify_in_c(.previous)

#define SOFT_MASK_TABLE(_start, _end)		\
	stringify_in_c(.section __soft_mask_table,"a";)\
	stringify_in_c(.balign 8;)		\
+1 −1
Original line number Diff line number Diff line
@@ -309,7 +309,7 @@ _GLOBAL(enter_rtas)
	 */
	lbz	r0,PACAIRQSOFTMASK(r13)
1:	tdeqi	r0,IRQS_ENABLED
	EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
	EMIT_WARN_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
#endif

	/* Hard-disable interrupts */
Loading