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 */ | ||||
| 	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 | ||||
|  |  | |||
|  | @ -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();				\ | ||||
| 	} else {						\ | ||||
| 		BUG_ENTRY(PPC_TLNEI " %4, 0",			\ | ||||
| 			  BUGFLAG_WARNING | BUGFLAG_TAINT(TAINT_WARN),	\ | ||||
| 			  "r" (__ret_warn_on));	\ | ||||
| 	}							\ | ||||
| 			__ret_warn_on = true;			\ | ||||
| 		} else {					\ | ||||
| 			__label__ __label_warn_on;		\ | ||||
| 								\ | ||||
| 			WARN_ENTRY(PPC_TLNEI " %4, 0",		\ | ||||
| 				   BUGFLAG_WARNING | BUGFLAG_TAINT(TAINT_WARN),	\ | ||||
| 				   __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 */ | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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;)		\ | ||||
|  |  | |||
|  | @ -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 */ | ||||
|  |  | |||
|  | @ -237,7 +237,7 @@ _GLOBAL(copy_page) | |||
| 	addi	r3,r3,-4 | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1477,8 +1477,13 @@ static void do_program_check(struct pt_regs *regs) | |||
| 
 | ||||
| 		if (!(regs->msr & MSR_PR) &&  /* not user-mode */ | ||||
| 		    report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) { | ||||
| 			regs_add_return_ip(regs, 4); | ||||
| 			return; | ||||
| 			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; | ||||
| 			} | ||||
| 		} | ||||
| 		_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); | ||||
| 		return; | ||||
|  |  | |||
|  | @ -931,7 +931,7 @@ static void check_section(const char *modname, struct elf_info *elf, | |||
| 		".kprobes.text", ".cpuidle.text", ".noinstr.text" | ||||
| #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ | ||||
| 		".fixup", ".entry.text", ".exception.text", ".text.*", \ | ||||
| 		".coldtext" | ||||
| 		".coldtext", ".softirqentry.text" | ||||
| 
 | ||||
| #define INIT_SECTIONS      ".init.*" | ||||
| #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
	
	 Christophe Leroy
						Christophe Leroy