forked from mirrors/linux
		
	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: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/389962b1b702e3c78d169e59bcfac56282889173.1618331882.git.christophe.leroy@csgroup.eu
			
			
This commit is contained in:
		
							parent
							
								
									db87a71992
								
							
						
					
					
						commit
						1e688dd2a3
					
				
					 9 changed files with 72 additions and 25 deletions
				
			
		| 
						 | 
					@ -90,7 +90,7 @@
 | 
				
			||||||
	/* Prevent access to userspace using any key values */
 | 
						/* Prevent access to userspace using any key values */
 | 
				
			||||||
	LOAD_REG_IMMEDIATE(\gpr2, AMR_KUAP_BLOCKED)
 | 
						LOAD_REG_IMMEDIATE(\gpr2, AMR_KUAP_BLOCKED)
 | 
				
			||||||
999:	tdne	\gpr1, \gpr2
 | 
					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)
 | 
						END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_BOOK3S_KUAP, 67)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#ifdef __KERNEL__
 | 
					#ifdef __KERNEL__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/asm-compat.h>
 | 
					#include <asm/asm-compat.h>
 | 
				
			||||||
 | 
					#include <asm/extable.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_BUG
 | 
					#ifdef CONFIG_BUG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +31,11 @@
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
#endif /* verbose */
 | 
					#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__ */
 | 
					#else /* !__ASSEMBLY__ */
 | 
				
			||||||
/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
 | 
					/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
 | 
				
			||||||
   sizeof(struct bug_entry), respectively */
 | 
					   sizeof(struct bug_entry), respectively */
 | 
				
			||||||
| 
						 | 
					@ -58,6 +64,16 @@
 | 
				
			||||||
		  "i" (sizeof(struct bug_entry)),	\
 | 
							  "i" (sizeof(struct bug_entry)),	\
 | 
				
			||||||
		  ##__VA_ARGS__)
 | 
							  ##__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
 | 
					 * BUG_ON() and WARN_ON() do their best to cooperate with compile-time
 | 
				
			||||||
 * optimisations. However depending on the complexity of the condition
 | 
					 * optimisations. However depending on the complexity of the condition
 | 
				
			||||||
| 
						 | 
					@ -70,7 +86,15 @@
 | 
				
			||||||
} while (0)
 | 
					} while (0)
 | 
				
			||||||
#define HAVE_ARCH_BUG
 | 
					#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
 | 
					#ifdef CONFIG_PPC64
 | 
				
			||||||
#define BUG_ON(x) do {						\
 | 
					#define BUG_ON(x) do {						\
 | 
				
			||||||
| 
						 | 
					@ -83,15 +107,24 @@
 | 
				
			||||||
} while (0)
 | 
					} while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WARN_ON(x) ({						\
 | 
					#define WARN_ON(x) ({						\
 | 
				
			||||||
	int __ret_warn_on = !!(x);				\
 | 
						bool __ret_warn_on = false;				\
 | 
				
			||||||
	if (__builtin_constant_p(__ret_warn_on)) {		\
 | 
						do {							\
 | 
				
			||||||
		if (__ret_warn_on)				\
 | 
							if (__builtin_constant_p((x))) {		\
 | 
				
			||||||
 | 
								if (!(x)) 				\
 | 
				
			||||||
 | 
									break; 				\
 | 
				
			||||||
			__WARN();				\
 | 
								__WARN();				\
 | 
				
			||||||
 | 
								__ret_warn_on = true;			\
 | 
				
			||||||
		} else {					\
 | 
							} else {					\
 | 
				
			||||||
		BUG_ENTRY(PPC_TLNEI " %4, 0",			\
 | 
								__label__ __label_warn_on;		\
 | 
				
			||||||
 | 
													\
 | 
				
			||||||
 | 
								WARN_ENTRY(PPC_TLNEI " %4, 0",		\
 | 
				
			||||||
				   BUGFLAG_WARNING | BUGFLAG_TAINT(TAINT_WARN),	\
 | 
									   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);				\
 | 
						unlikely(__ret_warn_on);				\
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,8 +137,11 @@
 | 
				
			||||||
#ifdef __ASSEMBLY__
 | 
					#ifdef __ASSEMBLY__
 | 
				
			||||||
.macro EMIT_BUG_ENTRY addr,file,line,flags
 | 
					.macro EMIT_BUG_ENTRY addr,file,line,flags
 | 
				
			||||||
.endm
 | 
					.endm
 | 
				
			||||||
 | 
					.macro EMIT_WARN_ENTRY addr,file,line,flags
 | 
				
			||||||
 | 
					.endm
 | 
				
			||||||
#else /* !__ASSEMBLY__ */
 | 
					#else /* !__ASSEMBLY__ */
 | 
				
			||||||
#define _EMIT_BUG_ENTRY
 | 
					#define _EMIT_BUG_ENTRY
 | 
				
			||||||
 | 
					#define _EMIT_WARN_ENTRY
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif /* CONFIG_BUG */
 | 
					#endif /* CONFIG_BUG */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ARCH_HAS_RELATIVE_EXTABLE
 | 
					#define ARCH_HAS_RELATIVE_EXTABLE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __ASSEMBLY__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct exception_table_entry {
 | 
					struct exception_table_entry {
 | 
				
			||||||
	int insn;
 | 
						int insn;
 | 
				
			||||||
	int fixup;
 | 
						int fixup;
 | 
				
			||||||
| 
						 | 
					@ -28,3 +30,15 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
#include <asm/ppc-opcode.h>
 | 
					#include <asm/ppc-opcode.h>
 | 
				
			||||||
#include <asm/firmware.h>
 | 
					#include <asm/firmware.h>
 | 
				
			||||||
#include <asm/feature-fixups.h>
 | 
					#include <asm/feature-fixups.h>
 | 
				
			||||||
 | 
					#include <asm/extable.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __ASSEMBLY__
 | 
					#ifdef __ASSEMBLY__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -752,16 +753,6 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /*  __ASSEMBLY__ */
 | 
					#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)		\
 | 
					#define SOFT_MASK_TABLE(_start, _end)		\
 | 
				
			||||||
	stringify_in_c(.section __soft_mask_table,"a";)\
 | 
						stringify_in_c(.section __soft_mask_table,"a";)\
 | 
				
			||||||
	stringify_in_c(.balign 8;)		\
 | 
						stringify_in_c(.balign 8;)		\
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -309,7 +309,7 @@ _GLOBAL(enter_rtas)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	lbz	r0,PACAIRQSOFTMASK(r13)
 | 
						lbz	r0,PACAIRQSOFTMASK(r13)
 | 
				
			||||||
1:	tdeqi	r0,IRQS_ENABLED
 | 
					1:	tdeqi	r0,IRQS_ENABLED
 | 
				
			||||||
	EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
 | 
						EMIT_WARN_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Hard-disable interrupts */
 | 
						/* Hard-disable interrupts */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -237,7 +237,7 @@ _GLOBAL(copy_page)
 | 
				
			||||||
	addi	r3,r3,-4
 | 
						addi	r3,r3,-4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
0:	twnei	r5, 0	/* WARN if r3 is not cache aligned */
 | 
					0:	twnei	r5, 0	/* WARN if r3 is not cache aligned */
 | 
				
			||||||
	EMIT_BUG_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING
 | 
						EMIT_WARN_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addi	r4,r4,-4
 | 
						addi	r4,r4,-4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1477,9 +1477,14 @@ static void do_program_check(struct pt_regs *regs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!(regs->msr & MSR_PR) &&  /* not user-mode */
 | 
							if (!(regs->msr & MSR_PR) &&  /* not user-mode */
 | 
				
			||||||
		    report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) {
 | 
							    report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) {
 | 
				
			||||||
			regs_add_return_ip(regs, 4);
 | 
								const struct exception_table_entry *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								entry = search_exception_tables(bugaddr);
 | 
				
			||||||
 | 
								if (entry) {
 | 
				
			||||||
 | 
									regs_set_return_ip(regs, extable_fixup(entry) + regs->nip - bugaddr);
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
 | 
							_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -931,7 +931,7 @@ static void check_section(const char *modname, struct elf_info *elf,
 | 
				
			||||||
		".kprobes.text", ".cpuidle.text", ".noinstr.text"
 | 
							".kprobes.text", ".cpuidle.text", ".noinstr.text"
 | 
				
			||||||
#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
 | 
					#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
 | 
				
			||||||
		".fixup", ".entry.text", ".exception.text", ".text.*", \
 | 
							".fixup", ".entry.text", ".exception.text", ".text.*", \
 | 
				
			||||||
		".coldtext"
 | 
							".coldtext", ".softirqentry.text"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define INIT_SECTIONS      ".init.*"
 | 
					#define INIT_SECTIONS      ".init.*"
 | 
				
			||||||
#define MEM_INIT_SECTIONS  ".meminit.*"
 | 
					#define MEM_INIT_SECTIONS  ".meminit.*"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								tools/testing/selftests/powerpc/primitives/asm/extable.h
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								tools/testing/selftests/powerpc/primitives/asm/extable.h
									
									
									
									
									
										Symbolic link
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					../../../../../../arch/powerpc/include/asm/extable.h
 | 
				
			||||||
		Loading…
	
		Reference in a new issue